void VImageState::OnPaint(VGraphicsInfo &Graphics, const VItemRenderInfo &parentState)
{
  VTextureObject *pTex = GetCurrentTexture();
  if (!pTex)
    return;

  VASSERT(parentState.m_pWindow);
  VRectanglef rect = parentState.m_pWindow->GetBoundingBox();
  VSimpleRenderState_t state = VGUIManager::DefaultGUIRenderState(m_eTranspType);
  VColorRef iColor = parentState.iFadeColor*m_iColor;
  state.SetFlag(m_iAdditionalStateFlags); // apply filtering for instance

  if (m_eStretchMode==BORDER)
  {
    hkvVec2 v1 = rect.m_vMin;
    hkvVec2 v2 = rect.m_vMax;
    float bx = (float)pTex->GetTextureWidth()*0.5f;
    float by = (float)pTex->GetTextureHeight()*0.5f;
    float hx = 1.f / bx;
    float hy = 1.f / by;
    bx -= 1.f;
    by -= 1.f;
    Overlay2DVertex_t v[(4+4+1)*6]; // 9 quads
    int iVertexCount = 0;

    // corners
    IVRender2DInterface::CreateQuadVertices(v1.x,v1.y, v1.x+bx,v1.y+by, 0,0,0.5f-hx,0.5f-hy, iColor, &v[iVertexCount]); iVertexCount+=6;
    IVRender2DInterface::CreateQuadVertices(v2.x-bx,v1.y, v2.x,v1.y+by, 0.5f+hx,0,1,0.5f-hy, iColor, &v[iVertexCount]); iVertexCount+=6;
    IVRender2DInterface::CreateQuadVertices(v2.x-bx,v2.y-by, v2.x,v2.y, 0.5f+hx,0.5f+hy,1,1, iColor, &v[iVertexCount]); iVertexCount+=6;
    IVRender2DInterface::CreateQuadVertices(v1.x,v2.y-by, v1.x+bx,v2.y, 0,0.5f+hy,0.5f-hx,1, iColor, &v[iVertexCount]); iVertexCount+=6;
  
    // edges
    IVRender2DInterface::CreateQuadVertices(v1.x+bx,v1.y, v2.x-bx,v1.y+by, 0.5f-hx,0,0.5f+hx,0.5f-hy, iColor, &v[iVertexCount]); iVertexCount+=6;
    IVRender2DInterface::CreateQuadVertices(v1.x+bx,v2.y-by, v2.x-bx,v2.y, 0.5f-hx,0.5f+hy,0.5f+hx,1, iColor, &v[iVertexCount]); iVertexCount+=6;
    IVRender2DInterface::CreateQuadVertices(v1.x,v1.y+by, v1.x+bx,v2.y-by, 0,0.5f-hy,0.5f-hx,0.5f+hy, iColor, &v[iVertexCount]); iVertexCount+=6;
    IVRender2DInterface::CreateQuadVertices(v2.x-bx,v1.y+by, v2.x,v2.y-by, 0.5f+hx,0.5f-hy,1,0.5f+hy, iColor, &v[iVertexCount]); iVertexCount+=6;
    
    // inner rect
    IVRender2DInterface::CreateQuadVertices(v1.x+bx,v1.y+by, v2.x-bx,v2.y-by, 0.5f-hx,0.5f-hy,0.5f+hx,0.5f+hy, iColor, &v[iVertexCount]); iVertexCount+=6;

    RENDER_VERTICES(iVertexCount);
  } 
  else if (m_eStretchMode==STRETCHED)
  {
    Overlay2DVertex_t v[6];    
    IVRender2DInterface::CreateQuadVertices(rect.m_vMin.x,rect.m_vMin.y,rect.m_vMax.x,rect.m_vMax.y,texCoord.m_vMin.x,texCoord.m_vMin.y,texCoord.m_vMax.x,texCoord.m_vMax.y,iColor,v);
    RENDER_VERTICES(6);
  }
  else // actual texture size
  {
    Overlay2DVertex_t v[6];
    rect.m_vMax.x = rect.m_vMin.x + (float)pTex->GetTextureWidth();
    rect.m_vMax.y = rect.m_vMin.y + (float)pTex->GetTextureHeight();
    IVRender2DInterface::CreateQuadVertices(rect.m_vMin.x,rect.m_vMin.y,rect.m_vMax.x,rect.m_vMax.y,texCoord.m_vMin.x,texCoord.m_vMin.y,texCoord.m_vMax.x,texCoord.m_vMax.y,iColor,v);
    RENDER_VERTICES(6);
  }
}
VTextureObject* VRestoreScreen::CreateBackgroundImage()
{
  // Auto mip map generation not supported on some devices for RGB8.
  VTextureObject* pTexture = Vision::TextureManager.Load2DTexture(GetSettings().m_sImagePath, VTM_FLAG_NO_MIPMAPS);
  if (pTexture != NULL)
  {
    pTexture->SetResourceFlag(VRESOURCEFLAG_AUTODELETE);
  }

  return pTexture;
}
void RPG_GuiManager_VisionGUI::AddSkillButtonsToParentDialog()
{
  InitializeButtonDefinitions();

  // add skill buttons
  for (int i = 0; i < BTN_Count; ++i)
  {
    VASSERT(!m_skillButtons[i]);
    m_skillButtons[i] = new VPushButton();
    VASSERT(m_skillButtons[i]);

    // button image(s)
    VTextureObject *buttonTexture = Vision::TextureManager.Load2DTexture(m_skillButtonDefinitions[i].m_imageFileName.AsChar());
    VASSERT_MSG(buttonTexture, "Button texture failed to load.");
    VASSERT_MSG(buttonTexture->IsTexturePowerOfTwo(), "Button texture's dimensions must be a power of two.");
    m_skillButtons[i]->Image().SetTexture(buttonTexture); // set all 4 textures for now
    m_skillButtons[i]->Image().SetTransparency(VIS_TRANSP_ALPHA);
    m_skillButtons[i]->Image().m_States[VWindowBase::MOUSEOVER].SetColor(VColorRef(128,128,255,255));
    m_skillButtons[i]->Image().m_States[VWindowBase::SELECTED].SetColor(VColorRef(208,24,24,255));
    m_skillButtons[i]->Image().m_States[VWindowBase::DISABLED].SetColor(VColorRef(128,128,128,255));

    // position, size and visibility
    hkvVec2 const position = FindButtonPosition(m_skillButtonDefinitions[i].m_positionOffsetFromCorner, m_skillButtonDefinitions[i].m_positionCorner);
    m_skillButtons[i]->SetPosition(position.x, position.y);
    m_skillButtons[i]->SetSize(m_skillButtonDefinitions[i].m_size.x, m_skillButtonDefinitions[i].m_size.y);
    m_skillButtons[i]->SetVisible(m_skillButtonDefinitions[i].m_initiallyVisible);

    VASSERT(m_parentDialog);
    m_parentDialog->AddControl(m_skillButtons[i]);
  }

#if defined(_VISION_MOBILE)
  MapTouchArea(m_skillButtons[BTN_RangedAttack], PI_ShiftModifier);
  MapTouchArea(m_skillButtons[BTN_PowerAttack], PI_SecondaryShiftModifier);
  MapTouchArea(m_skillButtons[BTN_AoeAttack], PI_SpecialAction01);
  MapTouchArea(m_skillButtons[BTN_RangedAttackAlt], PI_ShiftModifier);
  MapTouchArea(m_skillButtons[BTN_PowerAttackAlt], PI_SecondaryShiftModifier);
  MapTouchArea(m_skillButtons[BTN_AoeAttackAlt], PI_SpecialAction01);
#endif
}
void VCoronaManager::RenderCorona (VCoronaCandidate& coronaCandidate, VTextureObject*& pTexture)
{
#ifdef SUPPORTS_CORONAS
  VCoronaComponent *pCorona = coronaCandidate.m_pCorona;
  VisRenderContext_cl* pContext = VisRenderContext_cl::GetCurrentContext();
  VisLightSource_cl* pLight = (VisLightSource_cl*)pCorona->GetOwner();

  hkvVec3 vLightPos(hkvNoInitialization);
  pLight->GetVirtualPosition(vLightPos, pContext);
  hkvVec3 vEyePos(hkvNoInitialization);
  pContext->GetCamera()->GetPosition(vEyePos);
  hkvVec3 vDir = pContext->GetCamera()->GetDirection();

  // Corona texture
  VTextureObject *pTex = pCorona->GetCoronaTexture();
  if (pTex == NULL)
    return;

  if (pTexture != pTex)
  {
    pTexture = pTex;
    Vision::RenderLoopHelper.BindMeshTexture(pTexture,0);
  }

  // Get light color
  VColorRef color = pLight->GetColor();
  hkvVec3 vDist = vLightPos - vEyePos;
  float fEyeDist = vDir.dot(vDist);

  //determine if camera is in light cone if the light is directional
  float fDirectionalDampening = 1.0f;
  if ( pLight->GetType() == VIS_LIGHT_SPOTLIGHT && pCorona->GetOnlyVisibleInSpotLight() )
  {
    fDirectionalDampening = 0.0f;
    float fConeAngle = pLight->GetProjectionAngle();
    float fConeLength = pLight->GetRadius();
    hkvVec3 fConeDirection = pLight->GetDirection();
    fConeDirection.normalize();

    hkvVec3 vLightEyeDist = vEyePos - vLightPos;

    //#2 check if the camera is inside the angle of the cone
    float cosinusAngle = (vLightEyeDist/vLightEyeDist.getLength()).dot(fConeDirection);
    float fDegree = hkvMath::acosDeg(cosinusAngle);
    float normRadius = fDegree / (fConeAngle/2.0f);

    if (normRadius < 1.0f)
    {
      //hardcoded falloff. For better performance, we avoid sampling the projection texture here.
      const float fEpsilon = 64.0f/256.0f;
      const float fQuadFactor = 1.0f/fEpsilon - 1.0f;
      fDirectionalDampening = 1.0f / (1.0f + fQuadFactor*normRadius*normRadius);

      // scale the function so that the value is exactly 0.0 at the edge and 1.0 in the center
      fDirectionalDampening = (fDirectionalDampening - fEpsilon) / (1.0f - fEpsilon);  
    }
  }
  // Fog params
  float fFogDampening = 1.0f;
  if (pLight->GetType() != VIS_LIGHT_DIRECTED && Vision::World.IsLinearDepthFogEnabled())
  {  
    const VFogParameters &fog = Vision::World.GetFogParameters();
    float fFogStart = fog.fDepthStart;
    float fFogEnd = fog.fDepthEnd;

    float fFogFactor = (fFogEnd > fFogStart) ? ((fEyeDist - fFogStart) / (fFogEnd - fFogStart)) : 0.f;
    fFogDampening = 1.0f - hkvMath::clamp(fFogFactor, 0.0f, 1.0f);
  }

  // Get corona rotation
  float fRotation = 0.0f;
  hkvVec4 vRotation(1.0f, 0.0f, 0.0f, 1.0f);
  if (pCorona->CoronaFlags & VIS_CORONASCALE_ROTATING)
  { 
    fRotation = hkvMath::mod (fEyeDist * 0.5f, 360.f);

    vRotation.x = hkvMath::cosDeg (fRotation);
    vRotation.y = -hkvMath::sinDeg (fRotation);
    vRotation.z = -vRotation.y;
    vRotation.w = vRotation.x;
  }

  // Texture dimensions
  int iSizeX, iSizeY, depth;
  pTex->GetTextureDimensions(iSizeX, iSizeY, depth);

  hkvVec4 vScale(0.0f, 0.0f, 0.0f, 0.0f);

  int iMainWidth, iMainHeight, iWidth, iHeight;
  pContext->GetSize(iWidth, iHeight);
  VisRenderContext_cl::GetMainRenderContext()->GetSize(iMainWidth, iMainHeight);

  // Preserve texture aspect ratio
  int iTexHeight = pTex->GetTextureHeight();
  int iTexWidth = pTex->GetTextureWidth();

  // Perspective scaling
  // This scaling ensures roughly the same size on 720p as the old implementation.
  vScale.z = iTexWidth * pCorona->CoronaScaling * 0.25f;
  vScale.w = iTexHeight * pCorona->CoronaScaling * 0.25f;

  // Screen-space scaling
  // This scaling ensures roughly the same size on 720p as the old implementation.
  const float fScaleFactor = pCorona->CoronaScaling * iMainHeight / 11.0f;
  vScale.x = ((float)iTexWidth / 128.0f) * fScaleFactor * (float(iWidth) / float(iMainWidth));
  vScale.y = ((float)iTexHeight / 128.0f) * fScaleFactor * (float(iHeight) / float(iMainHeight));
  vScale.x *= 2.0f / iWidth;
  vScale.y *= 2.0f / iHeight;
  
  // Scale by visibility
  if (pCorona->CoronaFlags & VIS_CORONASCALE_VISIBLEAREA)
  {
    vScale.x *= coronaCandidate.m_fCurrentVisibility;
    vScale.y *= coronaCandidate.m_fCurrentVisibility;
    vScale.z *= coronaCandidate.m_fCurrentVisibility;
    vScale.w *= coronaCandidate.m_fCurrentVisibility;
  }

  VCompiledShaderPass* pShader = m_spCoronaTechnique->GetShader(0);
  VShaderConstantBuffer *pVertexConstBuffer = pShader->GetConstantBuffer(VSS_VertexShader);
  // xyz = worldspace position, w = 1.0 if VIS_CORONASCALE_DISTANCE is true, otherwise zero.
  pVertexConstBuffer->SetSingleParameterF("coronaPosition", vLightPos.x, vLightPos.y, vLightPos.z, (pCorona->CoronaFlags & VIS_CORONASCALE_DISTANCE) ? 1.0f : 0.0f);
  // xyz = light color, w = corona visibility.
  pVertexConstBuffer->SetSingleParameterF("coronaColor", color.r/255.0f, color.g/255.0f, color.b/255.0f, coronaCandidate.m_fCurrentVisibility * fFogDampening * fDirectionalDampening);
  // xyzw = 2x2 rotation matrix. float2x2 is not supported in shader model 2, so a float4 is used and multiplication is done manually in the shader.
  pVertexConstBuffer->SetSingleParameterF("coronaRotation", vRotation.x, vRotation.y, vRotation.z, vRotation.w);
  // xy = screen-space scaling. zw = view-space scaling.
  pVertexConstBuffer->SetSingleParameterF("coronaScale", vScale.x, vScale.y, vScale.z, vScale.w);
    
  Vision::RenderLoopHelper.RenderMeshes(pShader, VisMeshBuffer_cl::MB_PRIMTYPE_TRILIST, 0, 2, 6);
#endif
}
void VCoronaManager::UpdateCoronas(int iCoronaUpdateFlags)
{
#ifdef SUPPORTS_CORONAS

  VisRenderContext_cl* pContext = VisRenderContext_cl::GetCurrentContext();

  if ((iCoronaUpdateFlags & VCUF_USE_OC_CONTEXT) > 0)
  {
    // Determine relevant render context and visibility collector
    IVisVisibilityCollector_cl *pVisCollector = pContext->GetVisibilityCollector();
    if (!pVisCollector)
      return;
    VisRenderContext_cl *pOQContext = pVisCollector->GetOcclusionQueryRenderContext();
    if (pOQContext != NULL)
      pContext = pOQContext;
  }

  if (pContext == NULL)
    return;

  if ((pContext->GetRenderFlags() & VIS_RENDERCONTEXT_FLAG_USE_PIXELCOUNTER) == 0)
    return;

  if ((pContext->GetRenderFlags() & VIS_RENDERCONTEXT_FLAG_RENDER_CORONAS) == 0)
    return;

  // Get bitmask for this context.
  unsigned int iRenderFilterMask = pContext->GetRenderFilterMask();

  // get the collection of visible lights.
  IVisVisibilityCollector_cl* pVisCollector = VisRenderContext_cl::GetCurrentContext()->GetVisibilityCollector();
  if (pVisCollector == NULL)
    return;

  VISION_PROFILE_FUNCTION(PROFILING_CORONA_UPDATE);

  // Get multi-sampling mode
  unsigned int iTexelsPerPixel = 1;
  VTextureObject* pDepthTex = pContext->GetDepthStencilTarget();
  if(pDepthTex == NULL)
  {
    // If no depth stencil target is available, we might work without a renderer node and we're in the main context
    if(Vision::Renderer.GetCurrentRendererNode() == NULL && pContext == VisRenderContext_cl::GetMainRenderContext())
    {
      // In this case get the multi-sampling type from the video config as it's used to set the actual backbuffer settings
      // where the main context will render to
      iTexelsPerPixel = hkvMath::Max(1, 1 << ((int)Vision::Video.GetCurrentConfig()->m_eMultiSample));     
    }  
  }
  else if (pDepthTex->GetTextureType() == VTextureLoader::Texture2D)
  {
    iTexelsPerPixel = hkvMath::Max(1u, ((VisRenderableTexture_cl*)pDepthTex)->GetConfig()->m_iMultiSampling);
  }
  
  const VisLightSrcCollection_cl* pVisibleLights = pVisCollector->GetVisibleLights();
  int iCandidates = 0;
  if (pVisibleLights != NULL)
    iCandidates = pVisibleLights->GetNumEntries();

  // Ensure size of coronas state structure.
  int iContextIndex = pContext->GetNumber();
  if (iContextIndex + 1 > m_State.GetSize())
    m_State.SetSize(iContextIndex + 1, -1);
  VCoronaRenderContextState& state = m_State[iContextIndex];
  int iCapacity = m_Instances.GetCapacity();
  state.EnsureSize(iCapacity);

  // Add visible lights with a lens flare component to the candidate list for this frame
  if ((iCoronaUpdateFlags & VCUF_ADD) > 0)
  {
    for (int iCandidate = 0; iCandidate < iCandidates; ++iCandidate)
    {
      VisLightSource_cl* pLight = pVisibleLights->GetEntry(iCandidate);
      if (pLight)
      {
        VCoronaComponent *pComponent = pLight->Components().GetComponentOfBaseType<VCoronaComponent>();
        if (pComponent != NULL && pComponent->IsEnabled() && !state.IsBitSet(pComponent->m_iIndex))
        {
          // The component is not in m_Candidates yet, so we check whether it is a valid candidate
          bool bIsLightOnScreen = pComponent->IsValidCandidate(pContext);

          if (bIsLightOnScreen)
          {
            state.SetBit(pComponent->m_iIndex);
            pContext->SetPixelCounterResult(pComponent->m_CoronaPixelCounter.GetNumber(), 0);
            state.m_Candidates.Append(pComponent);
          }
        }
      }
    }
  }
  

  // Forces the retrieval all pending queries.
  pContext->FetchPixelCounterTestResults( (iCoronaUpdateFlags & VCUF_FORCE_FETCH) > 0 );
   
  
  // Retrieve Queries and update status of lens flares
  if ((iCoronaUpdateFlags & VCUF_UPDATE) > 0)
  {
    for (int i=0; i < state.m_Candidates.GetSize(); ++i)
    {
      VCoronaCandidate& coronaCandidate = state.m_Candidates.ElementAt(i);
      VCoronaComponent* pCorona = coronaCandidate.m_pCorona;
      if (!pCorona || !pCorona->IsEnabled())
        continue;

      if (pCorona->GetOwner())
      {
        // Retrieve occlusion results of the last query
        unsigned int iElementIndex = pCorona->m_CoronaPixelCounter.GetNumber();
        bool bRes = !pContext->IsPixelCounterQueryInProgress(iElementIndex);

        // Reschedule query if the old on could be retrieved or if a teleport forces us to re-query everything.
        if (bRes | ((iCoronaUpdateFlags & VCUF_FORCE_SCHEDULE) > 0) )
          pContext->SchedulePixelCounterTest(iElementIndex);

        unsigned int iDrawnPixels = pContext->GetPixelCounterResult(iElementIndex) / iTexelsPerPixel;

        float fVisibility = (float)iDrawnPixels / ((int)pCorona->QueryRadius * (int)pCorona->QueryRadius * 4);

        // ATI fix for random insanely high return values.
        if (iDrawnPixels > ((unsigned int)pCorona->QueryRadius * 2 + 1) * ((unsigned int)pCorona->QueryRadius * 2 + 1))
        {
          fVisibility = coronaCandidate.m_fLastVisibilityQuery;
        }

        if ((iCoronaUpdateFlags & VCUF_FORCE_FETCH) > 0)
        {
          // Force lens flare visibility to the current query value.
          coronaCandidate.m_fCurrentVisibility = fVisibility;
          coronaCandidate.m_fLastVisibilityQuery = fVisibility;
          pCorona->UpdateVisibility(coronaCandidate.m_fLastVisibilityQuery, coronaCandidate.m_fCurrentVisibility);
        }
        else if (!m_bTeleportedLastFrame)
        {
          coronaCandidate.m_fLastVisibilityQuery = fVisibility;
          pCorona->UpdateVisibility(coronaCandidate.m_fLastVisibilityQuery, coronaCandidate.m_fCurrentVisibility);
        }
        else
        {
          // if we were teleported, the last frame's query results must be invalidated
          coronaCandidate.m_fCurrentVisibility = 0.0f;
          coronaCandidate.m_fLastVisibilityQuery = 0.0f;
        }
      }
    }
  }
  
  // Removes coronas that are outside the frustum and no longer visible.
  if ((iCoronaUpdateFlags & VCUF_REMOVE) > 0)
  {
    for (int i=0; i < state.m_Candidates.GetSize();)
    {
      VCoronaCandidate& coronaCandidate = state.m_Candidates.ElementAt(i);
      VCoronaComponent* pCorona = coronaCandidate.m_pCorona;

      unsigned int iElementIndex = pCorona->m_CoronaPixelCounter.GetNumber();
      // If the visibility reached zero and the corona is no longer potentially visible it is removed from the list
      if (!pCorona->IsEnabled() || !pCorona->GetOwner()
        || (pCorona->GetVisibleBitmask() & iRenderFilterMask) == 0
        || (((VisLightSource_cl*)pCorona->GetOwner())->GetVisibleBitmask() & iRenderFilterMask) == 0
        || ( coronaCandidate.m_fCurrentVisibility == 0.0f && !pCorona->IsValidCandidate(pContext) ) )
      {
        state.RemoveBit(pCorona->m_iIndex);
        state.m_Candidates.SetAt(i, state.m_Candidates.GetAt(state.m_Candidates.GetSize()-1) );
        state.m_Candidates.RemoveAt(state.m_Candidates.GetSize() -1);
        // Reset cache to zero, so we don't see the lens flare once it enters the frustum again.
        pContext->SetPixelCounterResult(iElementIndex, 0);
      }
      else
      {
        ++i;
      }
    }
  }

#endif
}