Beispiel #1
0
void VPostProcessFXAA::Execute()
{
  if (!IsActive() || !m_bIsInitialized)
    return;
 
  INSERT_PERF_MARKER_SCOPE("FXAA");

  RenderingOptimizationHelpers_cl::SetShaderPreference(112);

  if (m_spFrameCopyTexture != NULL)
  {
    Vision::Renderer.CopyToTexture(m_spFrameCopyTexture, 0, 0, m_iWidth, m_iHeight);
  }

  VCompiledShaderPass *pPass = m_spMask->GetTechnique()->GetShader(0);
  VShaderConstantBuffer *pPS = pPass->GetConstantBuffer(VSS_PixelShader);

  hkvVec4 invScreenSize(1.0f / m_iWidth, 1.0f / m_iHeight, 0, 0);

  if (m_iRegScreenSize >= 0)
  {
    pPS->SetSingleRegisterF(m_iRegScreenSize, invScreenSize.data);
  }

  tempMasks.Clear();
  tempMasks.AppendEntryFast(m_spMask);
  Vision::RenderLoopHelper.RenderScreenMasks(tempMasks);
}
void VTerrainDecorationEntityModel::RenderBatchIR(VTerrainVisibilityCollectorComponent *pInfoComp, VTerrainDecorationInstance **pInstList, int iCount, RenderMode_e eRenderMode)
{
  // IR Rendering
  VTerrainDecorationModelManager* pManager = (VTerrainDecorationModelManager *)GetParentManager();
  VShaderEffectLib* pEffectLib = pManager->GetInfraredShaderLib();
  if (iCount > 0 && pManager->m_iInstancingBatchCount > 0 && pEffectLib != NULL)
  {
    int iMaxInstanceCount, iInstanceStreamMask;
    VisSurface_cl* pSurface = m_spMesh->GetSurface(0);

    if (m_spInstancingTechIRPrePass == NULL)
    {
      // lazy IR shader init
      RecreateIRShaders(pSurface, pEffectLib);
    }
    if (m_spInstancingTechIRPrePass == NULL || m_spInstancingTechIRMainPass == NULL)
      return;

    const int iPrimitiveCount = m_spModelMesh->GetCurrentPrimitiveCount();
    const int iVertexCount = m_spModelMesh->GetVertexCount();
    const VisMeshBuffer_cl::MB_PrimitiveType_e ePrimType = m_spModelMesh->GetPrimitiveType();

    bool bPrePass = (eRenderMode == RENDER_MODE_IR_PREPASS);
    VCompiledShaderPass* pShader = bPrePass? m_spInstancingTechIRPrePass->GetShader(0) : m_spInstancingTechIRMainPass->GetShader(0);
    
    const int iStreamMask = m_spModelMesh->GetStreamMask() & (pShader->GetStreamMask() | VERTEX_STREAM_INDEXBUFFER);
    VisMeshBuffer_cl* pInstanceMesh = pManager->GetInstanceBuffer(iMaxInstanceCount, iInstanceStreamMask);
    iInstanceStreamMask &= pShader->GetStreamMask();

    // perform the rendering
    Vision::RenderLoopHelper.BeginMeshRendering();

    Vision::RenderLoopHelper.BindDefaultStateGroups(pSurface, pShader);

    if (!bPrePass || pSurface->GetTransparencyType() != VIS_TRANSP_NONE)
      Vision::RenderLoopHelper.BindMeshTexture(pSurface->GetBaseTextureObject(), 0, NULL);

    while (iCount > 0)
    {
      int iRenderCount = hkvMath::Min(iCount, iMaxInstanceCount);

      // fill the instance buffer:
      {
        VISION_PROFILE_FUNCTION(VTerrainSectorManager::PROFILING_RENDERDECORARION_INSTANCE_SETUP);

        VModelInstanceData_t* pDest = (VModelInstanceData_t *)pInstanceMesh->LockVertices(VIS_LOCKFLAG_DISCARDABLE, 0, iRenderCount);
        for (int i = 0; i < iRenderCount; i++, pInstList++, pDest++)
          pDest->Set(*pInstList[0]);
        pInstanceMesh->UnLockVertices();
      }

      iCount -= iRenderCount;

      RENDER_INSTANCES(iRenderCount, iStreamMask);
    }

    Vision::RenderLoopHelper.EndMeshRendering();
  }
}
void VRendererNodeCommon::RenderSceneDepth(bool bHalfSize)
{
  PushAndDisableGlobalWireframeState();
  if (m_spDepthOnlyTechnique == NULL)
  {
    Vision::Shaders.LoadShaderLibrary("\\Shaders\\BaseShaders.ShaderLib", SHADERLIBFLAG_HIDDEN);
#ifdef _VISION_XENON
    m_spDepthOnlyTechnique360 = Vision::Shaders.CreateTechnique("CopyDepthOnly_360", NULL);
    VASSERT(m_spDepthOnlyTechnique360 != NULL);
#endif
    m_spDepthOnlyTechnique = Vision::Shaders.CreateTechnique("CopyDepthOnly", NULL);
    VASSERT(m_spDepthOnlyTechnique != NULL);
  }
#ifdef _VISION_XENON
  if(bHalfSize == false)
  {
    VASSERT_MSG(m_bDepthRestoreInitialized, "Fast depth restore has not been initialized");
    VisHiZHelper_cl::FastDepthRestore(m_fastRestoreData, m_spDepthOnlyTechnique360->GetShader(0), VisHiZHelper_cl::VR_HIZ_RESTORE);
  }
  else
  {
#endif
    IVRender2DInterface *pRenderer = Vision::RenderLoopHelper.BeginOverlayRendering();
    VCompiledShaderPass *pPass = m_spDepthOnlyTechnique->GetShader(0);
    VStateGroupTexture *pStateGroupTexture = pPass->GetStateGroupTexture(VSS_PixelShader, 0);

#ifdef _VISION_PS3
    if (m_spDummyDepthTexture == NULL)
      m_spDummyDepthTexture = RenderingOptimizationHelpers_cl::CreateAndPatchDummyTexture(m_spDepthReadTarget);
    if (pStateGroupTexture != NULL)
    {
      pStateGroupTexture->m_spCustomTex = m_spDummyDepthTexture;
      pPass->m_bModified = true;
    }
#else
    if (pStateGroupTexture != NULL)
    {
      pStateGroupTexture->m_spCustomTex = m_spDepthReadTarget;
      pPass->m_bModified = true;
    }
#endif

    Overlay2DVertex_t *pVertices;
    if (bHalfSize)
      pVertices = GetRendererNodeHelper()->GetOverlayVerticesHalfSize();
    else
      pVertices = GetRendererNodeHelper()->GetOverlayVertices();

    pRenderer->Draw2DBufferWithShader(6, pVertices, NULL, *pPass);

    Vision::RenderLoopHelper.EndOverlayRendering();
#ifdef _VISION_XENON
  }
#endif
  PopGlobalWireframeState();
}
void VPostProcessTranslucencies::BlendQuarterSizeIntoTarget(VCompiledTechnique* pTechnique)
{
  IVRender2DInterface *pRenderer = Vision::RenderLoopHelper.BeginOverlayRendering();
  VCompiledShaderPass *pPass = pTechnique->GetShader(0);
  VStateGroupTexture *pStateGroupTexture = pPass->GetStateGroupTexture(VSS_PixelShader, 0);
  if (pStateGroupTexture != NULL)
    pStateGroupTexture->m_spCustomTex = m_spLowResColorTexture;
  pRenderer->Draw2DBufferWithShader(6, GetOwner()->GetRendererNodeHelper()->GetOverlayVertices(), m_spLowResColorTexture, *pPass);
  Vision::RenderLoopHelper.EndOverlayRendering();
}
void VRendererNodeCommon::FreeCustomTextureRefs(VCompiledTechniquePtr &spTech)
{
  if (spTech==NULL)
    return;
  for (unsigned int i=0;i<spTech->GetShaderCount();i++)
  {
    VCompiledShaderPass *pPass = spTech->GetShader(0);
    const unsigned int iActiveSamplerCount = pPass->GetActiveSamplerCount(VSS_PixelShader);
    for (unsigned int j=0;j<iActiveSamplerCount;j++)
    {
      VStateGroupTexture *pStateGroupTexture = pPass->GetStateGroupTexture(VSS_PixelShader, j);
      VASSERT(pStateGroupTexture != NULL);
      pStateGroupTexture->m_spCustomTex = NULL;
      pPass->m_bModified = true;
    }
  }
  spTech = NULL; // smart pointer reference
}
void VTerrainDecorationEntityModel::RenderBatchOTW(VTerrainVisibilityCollectorComponent *pInfoComp, VTerrainDecorationInstance **pInstList, int iCount)
{
  // OTW rendering
  VTerrainDecorationModelManager *pManager = (VTerrainDecorationModelManager *)GetParentManager();
  if (m_spInstancingTech!=NULL && iCount>4 && pManager->m_iInstancingBatchCount>0 /* && bAllowInstancing*/)
  {
    VCompiledShaderPass *pShader = m_spInstancingTech->GetShader(0);

    Vision::RenderLoopHelper.BeginMeshRendering();
    VisSurface_cl *pSurface = m_spMesh->GetSurface(0);
    Vision::RenderLoopHelper.BindSurfaceTextures(pSurface,pShader,NULL);
    Vision::RenderLoopHelper.BindDefaultStateGroups(pSurface,pShader);
    VisMeshBuffer_cl::MB_PrimitiveType_e ePrimType = m_spModelMesh->GetPrimitiveType();
    int iPrimitiveCount = m_spModelMesh->GetCurrentPrimitiveCount();
    int iVertexCount = m_spModelMesh->GetVertexCount();
    int iMaxInstanceCount, iInstanceStreamMask;
    VisMeshBuffer_cl *pInstanceMesh = ((VTerrainDecorationModelManager *)GetParentManager())->GetInstanceBuffer(iMaxInstanceCount,iInstanceStreamMask);

    // lightmap version
    if (m_iLightmapSampler>=0 && pInfoComp!=NULL)
    {
#ifdef HK_DEBUG
      const VStateGroupTexture *pStateGroupTexture = pShader->GetStateGroupTexture(VSS_PixelShader, m_iLightmapSampler);
      VASSERT(pStateGroupTexture!=NULL && pStateGroupTexture->m_cTextureType==TEXTURETYPE_LIGHTMAP);
#endif

      VStateGroupSampler *pLMSampler = pShader->GetStateGroupSampler(VSS_PixelShader, m_iLightmapSampler);
      VTerrainSector *pLastSector = NULL;
      VTextureObject *pTerrainLightmap = NULL;
      const VTerrainConfig& config(pInfoComp->m_pTerrain->m_Config);
      VTerrainSectorManager &sectormanager(pInfoComp->m_pTerrain->m_SectorManager);
      while (iCount>0)
      {
        int iWantedRenderCount = hkvMath::Min(iCount,iMaxInstanceCount);
        int iRenderCount = 0;

        // fill the instance buffer:
        {
          VISION_PROFILE_FUNCTION(VTerrainSectorManager::PROFILING_RENDERDECORARION_INSTANCE_SETUP);
          VModelInstanceData_t *pDest = (VModelInstanceData_t *)pInstanceMesh->LockVertices(VIS_LOCKFLAG_DISCARDABLE,0,iWantedRenderCount);
          // fill buffer up to lightmap change
          for (int i=0;i<iWantedRenderCount;i++,iRenderCount++,pDest++)
          {
            if (pLastSector!=pInstList[i]->m_pOwnerSector)
            {
              pLastSector = pInstList[i]->m_pOwnerSector;
              VTextureObject *pNewLightmap = pLastSector->m_pMeshPage[0].GetSurfaceSafe().m_spModelLightmaps[0];
              if (pNewLightmap!=pTerrainLightmap)
              {
                if (iRenderCount>0) // start a new batch so break here
                  break;
              }
            }
            pDest->Set(*pInstList[i]);
          }
          pInstanceMesh->UnLockVertices();
        }

        // bind sector specific properties
        VTerrainSector *pStateSetupSector = pInstList[0]->m_pOwnerSector; // this is where the batch starts
        hkvVec4 vWorld2Sector(false);
        // transforms worldspace to sector 0..1 range
        config.GetWorldSpaceToSectorTransform(pStateSetupSector->m_iIndexX,pStateSetupSector->m_iIndexY,vWorld2Sector);
        sectormanager.SetWorld2SectorTransform(vWorld2Sector);
          // standard range -> lightmap
        const hkvVec4 vSector2LM = pStateSetupSector->GetLightmapScaleOffset();
        VisRenderStates_cl::VSSetModelUVToLightmap(vSector2LM.data);
        Vision::RenderLoopHelper.BindMeshTexture(pStateSetupSector->m_pMeshPage[0].GetSurfaceSafe().m_spModelLightmaps[0],m_iLightmapSampler,pLMSampler);

        // advance by actual render counts
        pInstList += iRenderCount;
        iCount-=iRenderCount;
        RENDER_INSTANCES(iRenderCount, m_iModelStreams);
      }

    }
    else // non-lightmapped version
    {
      while (iCount>0)
      {
        int iRenderCount = hkvMath::Min(iCount,iMaxInstanceCount);

        // fill the instance buffer:
        {
          VISION_PROFILE_FUNCTION(VTerrainSectorManager::PROFILING_RENDERDECORARION_INSTANCE_SETUP);
          VModelInstanceData_t *pDest = (VModelInstanceData_t *)pInstanceMesh->LockVertices(VIS_LOCKFLAG_DISCARDABLE,0,iRenderCount);
          for (int i=0;i<iRenderCount;i++,pInstList++,pDest++)
            pDest->Set(*pInstList[0]);
          pInstanceMesh->UnLockVertices();
        }

        iCount-=iRenderCount;
        RENDER_INSTANCES(iRenderCount, m_iModelStreams);
      }
    }

    Vision::RenderLoopHelper.EndMeshRendering();
    return;
  }

  //////////////////////////////////////////////////////////
  // Non-instancing  version

  const VisDrawCallInfo_t *pSurfaceShaderList;
  VDynamicMesh *pMesh = m_spMesh;
  VASSERT(m_spVegetationShaders!=NULL);
  VisShaderSet_cl *pSet = m_spVegetationShaders;
  int iAsmCount = pSet->GetShaderAssignmentList(&pSurfaceShaderList);
  VColorRef iLastColor;

  #ifdef _VR_DX11
    VisRenderStates_cl::SetVSConstantBuffer(7,&m_PerInstanceData);
  #endif

  if (m_bNeedsLightmap && pInfoComp!=NULL)
  {
    VTerrainSector *pLastSector = NULL;
    VTextureObject *pTerrainLightmap = NULL;
    const VTerrainConfig& config(pInfoComp->m_pTerrain->m_Config);
    VTerrainSectorManager &sectormanager(pInfoComp->m_pTerrain->m_SectorManager);

    Vision::RenderLoopHelper.BeginEntityRendering();
    for (int i=0;i<iCount;i++,pInstList++)
    {
      if (pLastSector!=(*pInstList)->m_pOwnerSector)
      {
        pLastSector = (*pInstList)->m_pOwnerSector;
        VTextureObject *pNewLightmap = pLastSector->m_pMeshPage[0].GetSurfaceSafe().m_spModelLightmaps[0];
        if (pNewLightmap!=pTerrainLightmap)
        {
          // assign new model lightmaps
          const int iSrfCount = m_spMesh->GetSurfaceCount();
          for (int j=0;j<iSrfCount;j++)
            m_spMesh->GetSurface(j)->m_spModelLightmaps[0] = pNewLightmap;

          // and also force a shader re-binding
          for (int j=0;j<iAsmCount;j++)
            pSurfaceShaderList[j].GetShader()->m_bModified=true;

          pTerrainLightmap = pNewLightmap;
        }

        hkvVec4 vWorld2Sector(false);
        // transforms worldspace to sector 0..1 range
        config.GetWorldSpaceToSectorTransform(pLastSector->m_iIndexX,pLastSector->m_iIndexY,vWorld2Sector);
        sectormanager.SetWorld2SectorTransform(vWorld2Sector);
          // standard range -> lightmap
        const hkvVec4 vSector2LM = pLastSector->GetLightmapScaleOffset();
        VisRenderStates_cl::VSSetModelUVToLightmap(vSector2LM.data);
      }

      // per instance tint color
      if (i==0 || iLastColor!=(*pInstList)->m_InstanceColor)
      {
        iLastColor = (*pInstList)->m_InstanceColor;
        VPerInstanceData_t &data(m_PerInstanceData.BeginUpdate());
          VColorRef::RGBA_To_Float((*pInstList)->m_InstanceColor, data.vPerInstanceColor);
        m_PerInstanceData.EndUpdate();
      #ifndef _VR_DX11
        VisRenderStates_cl::SetVSConstantBuffer(7,&m_PerInstanceData);
      #endif
      }

      // finally render object
      hkvMat4 transform((*pInstList)->m_Orientation,(*pInstList)->m_vPosition);
      Vision::RenderLoopHelper.RenderModelWithSurfaceShaderList(m_spMesh,transform.getPointer (),iAsmCount,pSurfaceShaderList);
    }
    VisRenderStates_cl::SetVSConstantBuffer(7,NULL);
    Vision::RenderLoopHelper.EndEntityRendering();
  }
  else
  {
    Vision::RenderLoopHelper.BeginEntityRendering();

    // no lightmaps -> simple loop 
    for (int i=0;i<iCount;i++,pInstList++)
    {
      // per instance tint color
      if (i==0 || iLastColor!=(*pInstList)->m_InstanceColor)
      {
        iLastColor = (*pInstList)->m_InstanceColor;
        VPerInstanceData_t &data(m_PerInstanceData.BeginUpdate());
          VColorRef::RGBA_To_Float((*pInstList)->m_InstanceColor, data.vPerInstanceColor);
        m_PerInstanceData.EndUpdate();
      #ifndef _VR_DX11
        VisRenderStates_cl::SetVSConstantBuffer(7,&m_PerInstanceData);
      #endif
      }
      hkvMat4 transform((*pInstList)->m_Orientation,(*pInstList)->m_vPosition);
      Vision::RenderLoopHelper.RenderModelWithSurfaceShaderList(m_spMesh,transform.getPointer(),iAsmCount,pSurfaceShaderList);
    }

    VisRenderStates_cl::SetVSConstantBuffer(7,NULL);

    Vision::RenderLoopHelper.EndEntityRendering();
  }
}
void VRendererNodeCommon::RenderSceneTextureWithDepth(bool bHalfSize)
{
  PushAndDisableGlobalWireframeState();

  if (m_spSceneDepthTechnique == NULL)
  {
    Vision::Shaders.LoadShaderLibrary("\\Shaders\\BaseShaders.ShaderLib", SHADERLIBFLAG_HIDDEN);
    m_spSceneDepthTechnique = Vision::Shaders.CreateTechnique("CopyWithDepthOutput", NULL);
    VASSERT(m_spSceneDepthTechnique != NULL);
  }

#ifdef _VISION_XENON
  if(bHalfSize)
  {
    // first make sure the stencil buffer is cleared.
    // we clear it to all 1's, and then reset all geometry pixels to 0
    // For this the shader simply checks a pixels depth and does a discard on sky pixels (depth == 1.0).
    // On all pixels that pass the test, the stencil value is set to zero.
    Vision::RenderLoopHelper.ClearScreen(VisRenderLoopHelper_cl::VCTF_DepthStencil, VColorRef (0, 0, 0, 0), 1.0f, 255);
#endif

    IVRender2DInterface *pRenderer = Vision::RenderLoopHelper.BeginOverlayRendering();
    VCompiledShaderPass *pPass = m_spSceneDepthTechnique->GetShader(0);
    VStateGroupTexture *pStateGroupTexture = pPass->GetStateGroupTexture(VSS_PixelShader, 0);
    if (pStateGroupTexture != NULL)
      pStateGroupTexture->m_spCustomTex = m_spColorReadTarget;

    pStateGroupTexture = pPass->GetStateGroupTexture(VSS_PixelShader, 1);
#ifdef _VISION_PS3
    if (m_spDummyDepthTexture == NULL)
      m_spDummyDepthTexture = RenderingOptimizationHelpers_cl::CreateAndPatchDummyTexture(m_spDepthReadTarget);
    if (pStateGroupTexture != NULL)
    {
      pStateGroupTexture->m_spCustomTex = m_spDummyDepthTexture;
      pPass->m_bModified = true;
    }
#else
    if (pStateGroupTexture != NULL)
    {
      pStateGroupTexture->m_spCustomTex = m_spDepthReadTarget;
      pPass->m_bModified = true;
    }
#endif

    Overlay2DVertex_t *pVertices;
    if (bHalfSize)
      pVertices = GetRendererNodeHelper()->GetOverlayVerticesHalfSize();
    else
      pVertices = GetRendererNodeHelper()->GetOverlayVertices();
    pRenderer->Draw2DBufferWithShader(6, pVertices, NULL, *pPass); 

    Vision::RenderLoopHelper.EndOverlayRendering();

#ifdef _VISION_XENON
  }
  else
  {
    if(m_spDepthOnlyTechnique360 == NULL)
    {
      m_spDepthOnlyTechnique360 = Vision::Shaders.CreateTechnique("CopyDepthOnly_360", NULL);
      VASSERT(m_spDepthOnlyTechnique360 != NULL);
    }
    VASSERT_MSG(m_bDepthRestoreInitialized, "Fast depth restore has not been initialized");
    //Restore color first (can't do this in one step because of a certification issue with Depth only rendering right after MRT rendering)
    RenderSceneTexture(bHalfSize);
    //Restore depth and stencil with xbox 360 specific implementation
    VisHiZHelper_cl::FastDepthRestore(m_fastRestoreData, m_spDepthOnlyTechnique360->GetShader(0));
  }
#endif

  PopGlobalWireframeState();
}
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
}