You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/AtomLyIntegration/CryRenderAtomShim/AtomShim_Renderer.cpp

1686 lines
55 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Implementation of the NULL renderer API
#include "CryRenderOther_precompiled.h"
#include "AtomShim_Renderer.h"
#include <IColorGradingController.h>
#include "IStereoRenderer.h"
#include "../Common/Textures/TextureManager.h"
#include <IEngineModule.h>
#include <CryExtension/Impl/ClassWeaver.h>
// init memory pool usage
#include "GraphicsPipeline/FurBendData.h"
#include <AzFramework/Render/RenderSystemBus.h>
#include <MathConversion.h>
#include <AzCore/Math/MatrixUtils.h>
#include <Atom/RHI/Factory.h>
#include <Atom/RPI.Public/View.h>
#include <Atom/RPI.Public/ViewportContext.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Public/RPISystemInterface.h>
#include <Atom/RPI.Public/RPIUtils.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/Image/StreamingImage.h>
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
#include <AzFramework/Asset/AssetSystemBus.h>
#include <random> //std::random_device
CCryNameTSCRC CTexture::s_sClassName = CCryNameTSCRC("CTexture");
CCryNameTSCRC CHWShader::s_sClassNameVS = CCryNameTSCRC("CHWShader_VS");
CCryNameTSCRC CHWShader::s_sClassNamePS = CCryNameTSCRC("CHWShader_PS");
CCryNameTSCRC CShader::s_sClassName = CCryNameTSCRC("CShader");
CAtomShimRenderer* gcpAtomShim = NULL;
#ifdef _DEBUG
// static array used to check that calls to Set2DMode and Unset2DMode are matched. (static array initialized to zeros automatically).
int s_isIn2DMode[RT_COMMAND_BUF_COUNT];
#endif
//////////////////////////////////////////////////////////////////////
class CNullColorGradingController
: public IColorGradingController
{
public:
virtual int LoadColorChart([[maybe_unused]] const char* pChartFilePath) const { return 0; }
virtual int LoadDefaultColorChart() const { return 0; }
virtual void UnloadColorChart([[maybe_unused]] int texID) const {}
virtual void SetLayers([[maybe_unused]] const SColorChartLayer* pLayers, [[maybe_unused]] uint32 numLayers) {}
};
//////////////////////////////////////////////////////////////////////
class CNullStereoRenderer
: public IStereoRenderer
{
public:
virtual EStereoDevice GetDevice() { return STEREO_DEVICE_NONE; }
virtual EStereoDeviceState GetDeviceState() { return STEREO_DEVSTATE_UNSUPPORTED_DEVICE; }
virtual void GetInfo(EStereoDevice* device, EStereoMode* mode, EStereoOutput* output, EStereoDeviceState* state) const
{
if (device)
{
*device = STEREO_DEVICE_NONE;
}
if (mode)
{
*mode = STEREO_MODE_NO_STEREO;
}
if (output)
{
*output = STEREO_OUTPUT_STANDARD;
}
if (state)
{
*state = STEREO_DEVSTATE_OK;
}
}
virtual bool GetStereoEnabled() { return false; }
virtual float GetStereoStrength() { return 0; }
virtual float GetMaxSeparationScene([[maybe_unused]] bool half = true) { return 0; }
virtual float GetZeroParallaxPlaneDist() { return 0; }
virtual void GetNVControlValues([[maybe_unused]] bool& stereoEnabled, [[maybe_unused]] float& stereoStrength) {};
virtual void OnHmdDeviceChanged() {}
virtual bool IsRenderingToHMD() override { return false; }
Status GetStatus() const override { return IStereoRenderer::Status::kIdle; }
};
//////////////////////////////////////////////////////////////////////
CAtomShimRenderer::CAtomShimRenderer()
{
gcpAtomShim = this;
m_pAtomShimRenderAuxGeom = CAtomShimRenderAuxGeom::Create(*this);
m_pAtomShimColorGradingController = new CNullColorGradingController();
m_pAtomShimStereoRenderer = new CNullStereoRenderer();
m_pixelAspectRatio = 1.0f;
Camera::ActiveCameraRequestBus::Handler::BusConnect();
}
//////////////////////////////////////////////////////////////////////////
bool QueryIsFullscreen()
{
return false;
}
#include <stdio.h>
namespace Platform
{
WIN_HWND GetNativeWindowHandle();
}
//////////////////////////////////////////////////////////////////////
CAtomShimRenderer::~CAtomShimRenderer()
{
Camera::ActiveCameraRequestBus::Handler::BusDisconnect();
ShutDown();
delete m_pAtomShimRenderAuxGeom;
delete m_pAtomShimColorGradingController;
delete m_pAtomShimStereoRenderer;
}
//////////////////////////////////////////////////////////////////////
void CAtomShimRenderer::EnableTMU([[maybe_unused]] bool enable)
{
}
//////////////////////////////////////////////////////////////////////
void CAtomShimRenderer::CheckError([[maybe_unused]] const char* comment)
{
}
//////////////////////////////////////////////////////////////////////
void CAtomShimRenderer::BeginFrame()
{
if (!m_isFinalInitializationDone)
{
// This will cause the default textures (such as the White texture) to be loaded. In legacy renderer it is called in CRenderer::PostInit
// but that is disabled for AtomShim because NULL_RENDERER is defined. Anyway, it would not work if we called it there because the Asset Catalog
// is not yet loaded when CRenderer::PostInit is called and we use it to load Atom textures.
// [GFX TODO] Do we want NULL_RENDERER defined for AtomShim? It would affect a lot of code in AtomShim if we removed that define.
InitSystemResources(FRR_SYSTEM_RESOURCES);
// In the legacy renderer this is done in CRenderer::PostInit but that is only done is NULL_RENDERER is not defined.
if (gEnv->pCryFont)
{
m_pDefaultFont = gEnv->pCryFont->GetFont("default");
if (!m_pDefaultFont)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Error getting default font");
}
}
AZ::Name apiName = AZ::RHI::Factory::Get().GetName();
if (!apiName.IsEmpty())
{
m_rendererDescription = AZStd::string::format("Atom using %s RHI", apiName.GetCStr());
}
// Initialize dynamic draw which is used for 2d drawing
const char* shaderFilepath = "Shaders/SimpleTextured.azshader";
m_dynamicDraw = AZ::RPI::DynamicDrawInterface::Get()->CreateDynamicDrawContext(
AZ::RPI::RPISystemInterface::Get()->GetDefaultScene().get());
AZ::Data::Instance<AZ::RPI::Shader> shader = AZ::RPI::LoadShader(shaderFilepath);
m_dynamicDraw->InitShader(shader);
m_dynamicDraw->InitVertexFormat(
{{"POSITION", AZ::RHI::Format::R32G32B32_FLOAT},
{"COLOR", AZ::RHI::Format::R8G8B8A8_UNORM},
{"TEXCOORD0", AZ::RHI::Format::R32G32_FLOAT}});
// enable the ability to change cull mode, blend mode, the depth state
m_dynamicDraw->AddDrawStateOptions( AZ::RPI::DynamicDrawContext::DrawStateOptions::BlendMode
| AZ::RPI::DynamicDrawContext::DrawStateOptions::PrimitiveType
| AZ::RPI::DynamicDrawContext::DrawStateOptions::DepthState
| AZ::RPI::DynamicDrawContext::DrawStateOptions::FaceCullMode);
m_dynamicDraw->EndInit();
// declare the two shader variants it will use
AZ::RPI::ShaderOptionList shaderOptionsClamp;
shaderOptionsClamp.push_back(AZ::RPI::ShaderOption(AZ::Name("o_useColorChannels"), AZ::Name("true")));
shaderOptionsClamp.push_back(AZ::RPI::ShaderOption(AZ::Name("o_clamp"), AZ::Name("true")));
m_shaderVariantClamp = m_dynamicDraw->UseShaderVariant(shaderOptionsClamp);
AZ::RPI::ShaderOptionList shaderOptionsWrap;
shaderOptionsWrap.push_back(AZ::RPI::ShaderOption(AZ::Name("o_useColorChannels"), AZ::Name("true")));
shaderOptionsWrap.push_back(AZ::RPI::ShaderOption(AZ::Name("o_clamp"), AZ::Name("false")));
m_shaderVariantWrap = m_dynamicDraw->UseShaderVariant(shaderOptionsWrap);
AZ::Data::Instance<AZ::RPI::ShaderResourceGroup> drawSrg = m_dynamicDraw->NewDrawSrg();
const AZ::RHI::ShaderResourceGroupLayout* layout = drawSrg->GetAsset()->GetLayout();
m_isFinalInitializationDone = true;
}
if (m_isInFrame)
{
// If there has not been an EndFrame since the latest BeginFrame then ignore this call to BeginFrame.
return;
}
m_isInFrame = true;
m_RP.m_TI[m_RP.m_nFillThreadID].m_nFrameID++;
m_RP.m_TI[m_RP.m_nFillThreadID].m_nFrameUpdateID++;
m_RP.m_TI[m_RP.m_nFillThreadID].m_RealTime = iTimer->GetCurrTime();
m_RP.m_TI[m_RP.m_nFillThreadID].m_matView.SetIdentity();
m_RP.m_TI[m_RP.m_nFillThreadID].m_matProj.SetIdentity();
m_pAtomShimRenderAuxGeom->BeginFrame();
}
//////////////////////////////////////////////////////////////////////
bool CAtomShimRenderer::ChangeDisplay([[maybe_unused]] unsigned int width, [[maybe_unused]] unsigned int height, [[maybe_unused]] unsigned int bpp)
{
return false;
}
//////////////////////////////////////////////////////////////////////
void CAtomShimRenderer::ChangeViewport(unsigned int x, unsigned int y, unsigned int width, unsigned int height, bool bMainViewport, float scaleWidth, float scaleHeight)
{
float fWidth = aznumeric_cast<float>(width);
float fHeight = aznumeric_cast<float>(height);
width = aznumeric_cast<unsigned int>(fWidth * scaleWidth);
height = aznumeric_cast<unsigned int>(fHeight * scaleHeight);
m_MainRTViewport.nX = x;
m_MainRTViewport.nY = y;
m_MainRTViewport.nWidth = width;
m_MainRTViewport.nHeight = height;
m_width = m_nativeWidth = m_backbufferWidth = width;
m_height = m_nativeHeight = m_backbufferHeight = height;
if (m_currContext)
{
m_currContext->m_width = width;
m_currContext->m_height = height;
m_currContext->m_isMainViewport = bMainViewport;
}
}
void CAtomShimRenderer::RenderDebug([[maybe_unused]] bool bRenderStats)
{
#if !defined(_RELEASE)
// debug render listeners
{
for (TListRenderDebugListeners::iterator itr = m_listRenderDebugListeners.begin();
itr != m_listRenderDebugListeners.end();
++itr)
{
(*itr)->OnDebugDraw();
}
}
#endif//_RELEASE
}
void CAtomShimRenderer::EndFrame()
{
if (!m_isInFrame)
{
// If there has not been a BeginFrame since the latest EndFrame then ignore this call to EndFrame.
// This can happen when EndFrame is called from UnloadLevel.
return;
}
m_pAtomShimRenderAuxGeom->EndFrame();
EF_RenderTextMessages();
// Hack: Assume we're just rendering to the default ViewContext
// Proper multi viewport support will be handled after this shim is removed
if (!m_viewportContext)
{
auto viewContextManager = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
auto viewportContext = viewContextManager->GetViewportContextByName(viewContextManager->GetDefaultViewportContextName());
// If the viewportContext exists and is created with the default ID, we can safely assume control
if (viewportContext && viewportContext->GetId() == -10)
{
m_viewportContext = viewportContext;
}
}
if (m_viewportContext)
{
m_viewportContext->SetRenderScene(AZ::RPI::RPISystemInterface::Get()->GetDefaultScene());
m_viewportContext->RenderTick();
}
m_isInFrame = false;
}
void CAtomShimRenderer::TryFlush()
{
}
void CAtomShimRenderer::GetMemoryUsage([[maybe_unused]] ICrySizer* Sizer)
{
}
WIN_HWND CAtomShimRenderer::GetHWND()
{
return Platform::GetNativeWindowHandle();
}
bool CAtomShimRenderer::SetWindowIcon([[maybe_unused]] const char* path)
{
return false;
}
ERenderType CAtomShimRenderer::GetRenderType() const
{
return eRT_Undefined;
}
const char* CAtomShimRenderer::GetRenderDescription() const
{
return m_rendererDescription.c_str();
}
void TexBlurAnisotropicVertical([[maybe_unused]] CTexture* pTex, [[maybe_unused]] int nAmount, [[maybe_unused]] float fScale, [[maybe_unused]] float fDistribution, [[maybe_unused]] bool bAlphaOnly)
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
//IMAGES DRAWING
////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
void CAtomShimRenderer::Draw2dImage([[maybe_unused]] float xpos, [[maybe_unused]] float ypos, [[maybe_unused]] float w, [[maybe_unused]] float h, [[maybe_unused]] int texture_id, [[maybe_unused]] float s0, [[maybe_unused]] float t0, [[maybe_unused]] float s1, [[maybe_unused]] float t1, [[maybe_unused]] float angle, [[maybe_unused]] float r, [[maybe_unused]] float g, [[maybe_unused]] float b, [[maybe_unused]] float a, [[maybe_unused]] float z)
{
}
//////////////////////////////////////////////////////////////////////
void CAtomShimRenderer::Push2dImage([[maybe_unused]] float xpos, [[maybe_unused]] float ypos, [[maybe_unused]] float w, [[maybe_unused]] float h, [[maybe_unused]] int texture_id, [[maybe_unused]] float s0, [[maybe_unused]] float t0, [[maybe_unused]] float s1, [[maybe_unused]] float t1, [[maybe_unused]] float angle, [[maybe_unused]] float r, [[maybe_unused]] float g, [[maybe_unused]] float b, [[maybe_unused]] float a, [[maybe_unused]] float z, [[maybe_unused]] float stereoDepth)
{
}
void CAtomShimRenderer::Draw2dImageList()
{
}
//////////////////////////////////////////////////////////////////////
void CAtomShimRenderer::DrawImage(float xpos, float ypos, float w, float h, int texture_id, float s0, float t0, float s1, float t1, float r, float g, float b, float a, bool filtered)
{
float s[4], t[4];
s[0] = s0;
t[0] = 1.0f - t0;
s[1] = s1;
t[1] = 1.0f - t0;
s[2] = s1;
t[2] = 1.0f - t1;
s[3] = s0;
t[3] = 1.0f - t1;
DrawImageWithUV(xpos, ypos, 0, w, h, texture_id, s, t, r, g, b, a, filtered);
}
///////////////////////////////////////////
void CAtomShimRenderer::DrawImageWithUV(float xpos, float ypos, float z, float w, float h, int texture_id, float s[4], float t[4], float r, float g, float b, float a, bool filtered)
{
float fx = xpos;
float fy = ypos;
float fw = w;
float fh = h;
SetCullMode(R_CULL_DISABLE);
EF_SetColorOp(eCO_MODULATE, eCO_MODULATE, DEF_TEXARG0, DEF_TEXARG0);
EF_SetSrgbWrite(false);
DWORD col = D3DRGBA(r, g, b, a);
SVF_P3F_C4B_T2F vQuad[4];
vQuad[0].xyz.x = xpos;
vQuad[0].xyz.y = ypos;
vQuad[0].xyz.z = z;
vQuad[0].st = Vec2(s[0], t[0]);
vQuad[0].color.dcolor = col;
vQuad[1].xyz.x = xpos + w;
vQuad[1].xyz.y = ypos;
vQuad[1].xyz.z = z;
vQuad[1].st = Vec2(s[1], t[1]);
vQuad[1].color.dcolor = col;
vQuad[2].xyz.x = xpos;
vQuad[2].xyz.y = ypos + h;
vQuad[2].xyz.z = z;
vQuad[2].st = Vec2(s[3], t[3]);
vQuad[2].color.dcolor = col;
vQuad[3].xyz.x = xpos + w;
vQuad[3].xyz.y = ypos + h;
vQuad[3].xyz.z = z;
vQuad[3].st = Vec2(s[2], t[2]);
vQuad[3].color.dcolor = col;
STexState TS;
TS.SetFilterMode(filtered ? FILTER_BILINEAR : FILTER_POINT);
TS.SetClampMode(1, 1, 1);
SetTexture(texture_id);
DrawDynVB(vQuad, nullptr, 4, 0, prtTriangleStrip);
}
///////////////////////////////////////////
void CAtomShimRenderer::DrawBuffer([[maybe_unused]] CVertexBuffer* pVBuf, [[maybe_unused]] CIndexBuffer* pIBuf, [[maybe_unused]] int nNumIndices, [[maybe_unused]] int nOffsIndex, [[maybe_unused]] const PublicRenderPrimitiveType nPrmode, [[maybe_unused]] int nVertStart, [[maybe_unused]] int nVertStop)
{
}
///////////////////////////////////////////
void CAtomShimRenderer::DrawPrimitivesInternal([[maybe_unused]] CVertexBuffer* src, [[maybe_unused]] int vert_num, [[maybe_unused]] const eRenderPrimitiveType prim_type)
{
}
///////////////////////////////////////////
void CRenderMesh::DrawImmediately()
{
}
///////////////////////////////////////////
void CAtomShimRenderer::SetCullMode(int mode)
{
AZ::RHI::CullMode cullMode = AZ::RHI::CullMode::None;
switch (mode)
{
case R_CULL_FRONT:
cullMode = AZ::RHI::CullMode::Front;
break;
case R_CULL_BACK:
cullMode = AZ::RHI::CullMode::Back;
break;
}
m_dynamicDraw->SetCullMode(cullMode);
}
///////////////////////////////////////////
bool CAtomShimRenderer::EnableFog([[maybe_unused]] bool enable)
{
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
//MISC EXTENSIONS
////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////
void CAtomShimRenderer::EnableVSync([[maybe_unused]] bool enable)
{
}
//////////////////////////////////////////////////////////////////////
void CAtomShimRenderer::SelectTMU([[maybe_unused]] int tnum)
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
//MATRIX FUNCTIONS
////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////
void CAtomShimRenderer::PushMatrix()
{
}
///////////////////////////////////////////
void CAtomShimRenderer::RotateMatrix([[maybe_unused]] float a, [[maybe_unused]] float x, [[maybe_unused]] float y, [[maybe_unused]] float z)
{
}
void CAtomShimRenderer::RotateMatrix([[maybe_unused]] const Vec3& angles)
{
}
///////////////////////////////////////////
void CAtomShimRenderer::TranslateMatrix([[maybe_unused]] float x, [[maybe_unused]] float y, [[maybe_unused]] float z)
{
}
void CAtomShimRenderer::MultMatrix([[maybe_unused]] const float* mat)
{
}
void CAtomShimRenderer::TranslateMatrix([[maybe_unused]] const Vec3& pos)
{
}
///////////////////////////////////////////
void CAtomShimRenderer::ScaleMatrix([[maybe_unused]] float x, [[maybe_unused]] float y, [[maybe_unused]] float z)
{
}
///////////////////////////////////////////
void CAtomShimRenderer::PopMatrix()
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
void CAtomShimRenderer::LoadMatrix([[maybe_unused]] const Matrix34* src)
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
//MISC
////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////
void CAtomShimRenderer::PushWireframeMode([[maybe_unused]] int mode){}
void CAtomShimRenderer::PopWireframeMode(){}
void CAtomShimRenderer::FX_PushWireframeMode([[maybe_unused]] int mode){}
void CAtomShimRenderer::FX_PopWireframeMode(){}
void CAtomShimRenderer::FX_SetWireframeMode([[maybe_unused]] int mode){}
///////////////////////////////////////////
void CAtomShimRenderer::SetCamera(const CCamera& cam)
{
CacheCameraConfiguration(cam);
CacheCameraTransform(cam);
int nThreadID = m_pRT->GetThreadList();
// Ortho-normalize camera matrix in double precision to minimize numerical errors and improve precision when inverting matrix
Matrix34_tpl<f64> mCam34 = cam.GetMatrix();
mCam34.OrthonormalizeFast();
Matrix44_tpl<f64> mCam44T = mCam34.GetTransposed();
Matrix44_tpl<f64> mView64;
mathMatrixLookAtInverse(&mView64, &mCam44T);
Matrix44 mView = (Matrix44_tpl<f32>)mView64;
// Rotate around x-axis by -PI/2
Matrix44 mViewFinal = mView;
mViewFinal.m01 = mView.m02;
mViewFinal.m02 = -mView.m01;
mViewFinal.m11 = mView.m12;
mViewFinal.m12 = -mView.m11;
mViewFinal.m21 = mView.m22;
mViewFinal.m22 = -mView.m21;
mViewFinal.m31 = mView.m32;
mViewFinal.m32 = -mView.m31;
Matrix44A* m = &m_RP.m_TI[nThreadID].m_matView;
m_RP.m_TI[nThreadID].m_matView = mViewFinal;
mViewFinal.m30 = 0;
mViewFinal.m31 = 0;
mViewFinal.m32 = 0;
m_CameraZeroMatrix[nThreadID] = mViewFinal;
if (m_RP.m_TI[nThreadID].m_PersFlags & RBPF_MIRRORCAMERA)
{
Matrix44A tmp;
tmp = Matrix44A(Matrix33::CreateScale(Vec3(1, -1, 1))).GetTransposed();
m_RP.m_TI[nThreadID].m_matView = tmp * m_RP.m_TI[nThreadID].m_matView;
}
m_RP.m_TI[nThreadID].m_cam = cam;
CameraViewParameters viewParameters;
// Asymmetric frustum
float Near = cam.GetNearPlane(), Far = cam.GetFarPlane();
float wT = tanf(cam.GetFov() * 0.5f) * Near, wB = -wT;
float wR = wT * cam.GetProjRatio(), wL = -wR;
viewParameters.Frustum(wL + cam.GetAsymL(), wR + cam.GetAsymR(), wB + cam.GetAsymB(), wT + cam.GetAsymT(), Near, Far);
Vec3 vEye = cam.GetPosition();
Vec3 vAt = vEye + Vec3((f32)mCam34(0, 1), (f32)mCam34(1, 1), (f32)mCam34(2, 1));
Vec3 vUp = Vec3((f32)mCam34(0, 2), (f32)mCam34(1, 2), (f32)mCam34(2, 2));
viewParameters.LookAt(vEye, vAt, vUp);
ApplyViewParameters(viewParameters);
// Set the Atom view for the context to match the given camera
{
AZ::RPI::ViewPtr viewForCurrentContext;
// If we have a current context (which we have in Editor but not yet in launcher) then use the view from that.
// Otherwise use the default view from the default scene.
if (m_currContext && m_currContext->m_view)
{
viewForCurrentContext = m_currContext->m_view;
}
else
{
AZ::RPI::ScenePtr scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene();
AZ::RPI::RenderPipelinePtr renderPipeline = scene->GetDefaultRenderPipeline();
if (renderPipeline)
{
viewForCurrentContext = renderPipeline->GetDefaultView();
}
}
if (viewForCurrentContext)
{
// Set camera to world transform for view
AZ::Matrix3x4 cameraWorldTransform = LYTransformToAZMatrix3x4(cam.GetMatrix());
viewForCurrentContext->SetCameraTransform(cameraWorldTransform);
// Set projection transform for view
// [GFX TODO] [ATOM-1501] Currently we always assume reverse depth
float fov = cam.GetFov();
float aspectRatio = cam.GetProjRatio();
float nearPlane = cam.GetNearPlane();
float farPlane = cam.GetFarPlane();
AZ::Matrix4x4 viewToClipMatrix;
AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, fov, aspectRatio, nearPlane, farPlane, true);
viewForCurrentContext->SetViewToClipMatrix(viewToClipMatrix);
}
}
}
void CAtomShimRenderer::GetViewport(int* x, int* y, int* width, int* height) const
{
const SViewport& vp = m_MainRTViewport;
*x = vp.nX;
*y = vp.nY;
*width = vp.nWidth;
*height = vp.nHeight;
}
void CAtomShimRenderer::SetViewport(int x, int y, int width, int height, [[maybe_unused]] int id)
{
m_MainRTViewport.nX = x;
m_MainRTViewport.nY = y;
m_MainRTViewport.nWidth = width;
m_MainRTViewport.nHeight = height;
m_width = width;
m_height = height;
}
void CAtomShimRenderer::SetScissor(int x, int y, int width, int height)
{
m_dynamicDraw->SetScissor(AZ::RHI::Scissor(x, y, x + width, y + height));
}
//////////////////////////////////////////////////////////////////////
void CAtomShimRenderer::GetModelViewMatrix(float* mat)
{
int nThreadID = m_pRT->GetThreadList();
*(Matrix44*)mat = m_RP.m_TI[nThreadID].m_matView;
}
//////////////////////////////////////////////////////////////////////
void CAtomShimRenderer::GetProjectionMatrix(float* mat)
{
int nThreadID = m_pRT->GetThreadList();
*(Matrix44*)mat = m_RP.m_TI[nThreadID].m_matProj;
}
//////////////////////////////////////////////////////////////////////
void CAtomShimRenderer::SetMatrices(float* pProjMat, float* pViewMat)
{
int nThreadID = m_pRT->GetThreadList();
m_RP.m_TI[nThreadID].m_matProj = *(Matrix44*)pProjMat;
m_RP.m_TI[nThreadID].m_matView = *(Matrix44*)pViewMat;
}
//////////////////////////////////////////////////////////////////////
void CAtomShimRenderer::ApplyViewParameters(const CameraViewParameters& viewParameters)
{
int nThreadID = m_pRT->GetThreadList();
m_RP.m_TI[nThreadID].m_cam.m_viewParameters = viewParameters;
Matrix44A* m = &m_RP.m_TI[nThreadID].m_matView;
viewParameters.GetModelviewMatrix((float*)m);
if (m_RP.m_TI[nThreadID].m_PersFlags & RBPF_MIRRORCAMERA)
{
Matrix44A tmp;
tmp = Matrix44A(Matrix33::CreateScale(Vec3(1, -1, 1))).GetTransposed();
m_RP.m_TI[nThreadID].m_matView = tmp * m_RP.m_TI[nThreadID].m_matView;
}
m = &m_RP.m_TI[nThreadID].m_matProj;
const bool bReverseDepth = true; // [GFX TODO] [ATOM-1501] Currently we always assume reverse depth
const bool bWasReverseDepth = (m_RP.m_TI[nThreadID].m_PersFlags & RBPF_REVERSE_DEPTH) != 0 ? 1 : 0;
m_RP.m_TI[nThreadID].m_PersFlags &= ~RBPF_REVERSE_DEPTH;
if (bReverseDepth)
{
mathMatrixPerspectiveOffCenterReverseDepth((Matrix44A*)m, viewParameters.fWL, viewParameters.fWR, viewParameters.fWB, viewParameters.fWT, viewParameters.fNear, viewParameters.fFar);
m_RP.m_TI[nThreadID].m_PersFlags |= RBPF_REVERSE_DEPTH;
}
}
// Check if a file exists. This does not go through the AssetCatalog so that it can identify files that exist but aren't processed yet,
// and so that it will work before the AssetCatalog has loaded
bool CheckIfFileExists(const AZStd::string& sourceRelativePath, const AZStd::string& cacheRelativePath)
{
// If the file exists, it has already been processed and does not need to be modified
bool fileExists = AZ::IO::FileIOBase::GetInstance()->Exists(cacheRelativePath.c_str());
if (!fileExists)
{
// If the texture doesn't exist check if it's queued or being compiled.
AzFramework::AssetSystem::AssetStatus status;
AzFramework::AssetSystemRequestBus::BroadcastResult(status, &AzFramework::AssetSystemRequestBus::Events::GetAssetStatus, sourceRelativePath);
switch (status)
{
case AzFramework::AssetSystem::AssetStatus_Queued:
case AzFramework::AssetSystem::AssetStatus_Compiling:
case AzFramework::AssetSystem::AssetStatus_Compiled:
case AzFramework::AssetSystem::AssetStatus_Failed:
{
// The file is queued, in progress, or finished processing after the initial FileIO check
fileExists = true;
break;
}
case AzFramework::AssetSystem::AssetStatus_Unknown:
case AzFramework::AssetSystem::AssetStatus_Missing:
default:
{
// The file does not exist
fileExists = false;
break;
}
}
}
return fileExists;
}
//////////////////////////////////////////////////////////////////////
ITexture* CAtomShimRenderer::EF_LoadTexture(const char * nameTex, const uint32 flags)
{
AtomShimTexture* atomTexture = nullptr;
// have to see if it is already loaded
CBaseResource* pBR = CBaseResource::GetResource(CTexture::mfGetClassName(), nameTex, false);
if (pBR)
{
// if a texture with this ID exists but it is not an Atom texture then we return nullptr
CTexture* texture = static_cast<CTexture*>(pBR);
AtomShimTexture* atomTexture2 = CastITextureToAtomShimTexture(texture);
if (atomTexture2)
{
atomTexture2->AddRef();
return atomTexture2;
}
else
{
return nullptr;
}
}
AZ_Error("CAtomShimRenderer", AzFramework::StringFunc::Path::IsRelative(nameTex), "CAtomShimRenderer::EF_LoadTexture assumes that it will always be given a relative path, but got '%s'", nameTex);
atomTexture = new AtomShimTexture(flags);
atomTexture->Register(CTexture::mfGetClassName(), nameTex);
atomTexture->SetSourceName( nameTex ); // needs to be normalized?
AZStd::string sourceRelativePath(nameTex);
AZStd::string cacheRelativePath = sourceRelativePath + ".streamingimage";
bool textureExists = false;
textureExists = CheckIfFileExists(sourceRelativePath, cacheRelativePath);
if(!textureExists)
{
// A lot of cry code uses the .dds extension even when the actual source file is .tif.
// For the .streamingimage file we need the correct source extension before .streamingimage
// So if the file doesn't exist and the extension was .dds then try replacing it with .tif
AZStd::string extension;
AzFramework::StringFunc::Path::GetExtension(nameTex, extension, false);
if (extension == "dds")
{
sourceRelativePath = nameTex;
static const char* textureExtensions[] = { "png", "tif", "tiff", "tga", "jpg", "jpeg", "bmp", "gif" };
for (const char* extensionReplacement : textureExtensions)
{
AzFramework::StringFunc::Path::ReplaceExtension(sourceRelativePath, extensionReplacement);
cacheRelativePath = sourceRelativePath + ".streamingimage";
textureExists = CheckIfFileExists(sourceRelativePath, cacheRelativePath);
if (textureExists)
{
break;
}
}
}
}
if(!textureExists)
{
AZ_Error("CAtomShimRenderer", false, "EF_LoadTexture attempted to load '%s', but it does not exist.", nameTex);
// Since neither the given extension nor the .dds version exist, we'll default to the given extension for hot-reloading in case the file is added to the source folder later
sourceRelativePath = nameTex;
cacheRelativePath = sourceRelativePath + ".streamingimage";
}
// now load the texture
// NOTE: CTexture::CreateTexture does the actual setting of texture data in Cry D3D case
// But it also calls CreateDeviceTexture
{
using namespace AZ;
// The file may not be in the AssetCatalog at this point if it is still processing or doesn't exist on disk.
// Use GenerateAssetIdTEMP instead of GetAssetIdByPath so that it will return a valid AssetId anyways
Data::AssetId streamingImageAssetId;
Data::AssetCatalogRequestBus::BroadcastResult(
streamingImageAssetId, &Data::AssetCatalogRequestBus::Events::GenerateAssetIdTEMP,
sourceRelativePath.c_str());
streamingImageAssetId.m_subId = RPI::StreamingImageAsset::GetImageAssetSubId();
auto streamingImageAsset = Data::AssetManager::Instance().FindOrCreateAsset<RPI::StreamingImageAsset>(streamingImageAssetId, AZ::Data::AssetLoadBehavior::PreLoad);
if (!streamingImageAsset.IsReady())
{
atomTexture->QueueForHotReload(streamingImageAssetId);
}
else
{
atomTexture->CreateFromStreamingImageAsset(streamingImageAsset);
}
}
atomTexture->SetTexStates();
return atomTexture;
}
//////////////////////////////////////////////////////////////////////
ITexture* CAtomShimRenderer::EF_LoadDefaultTexture(const char * nameTex)
{
return CTextureManager::Instance()->GetDefaultTexture(nameTex);
}
//////////////////////////////////////////////////////////////////////
void CAtomShimRenderer::DrawQuad([[maybe_unused]] const Vec3& right, [[maybe_unused]] const Vec3& up, [[maybe_unused]] const Vec3& origin, [[maybe_unused]] int nFlipmode /*=0*/)
{
}
//////////////////////////////////////////////////////////////////////
bool CAtomShimRenderer::ProjectToScreen(float ptx, float pty, float ptz, float* sx, float* sy, float* sz)
{
int nThreadID = m_pRT->GetThreadList();
SViewport& vp = m_MainRTViewport;
Vec3 vOut, vIn;
vIn.x = ptx;
vIn.y = pty;
vIn.z = ptz;
int32 v[4];
v[0] = vp.nX;
v[1] = vp.nY;
v[2] = vp.nWidth;
v[3] = vp.nHeight;
Matrix44A mIdent;
mIdent.SetIdentity();
if (mathVec3Project(
&vOut,
&vIn,
v,
&m_RP.m_TI[nThreadID].m_matProj,
&m_RP.m_TI[nThreadID].m_matView,
&mIdent))
{
*sx = vOut.x * 100 / vp.nWidth;
*sy = vOut.y * 100 / vp.nHeight;
*sz = (m_RP.m_TI[nThreadID].m_PersFlags & RBPF_REVERSE_DEPTH) ? 1.0f - vOut.z : vOut.z;
return true;
}
return false;
}
static bool InvertMatrixPrecise(Matrix44& out, const float* m)
{
// Inverts matrix using Gaussian Elimination which is slower but numerically more stable than Cramer's Rule
float expmat[4][8] = {
{ m[0], m[4], m[8], m[12], 1.f, 0.f, 0.f, 0.f },
{ m[1], m[5], m[9], m[13], 0.f, 1.f, 0.f, 0.f },
{ m[2], m[6], m[10], m[14], 0.f, 0.f, 1.f, 0.f },
{ m[3], m[7], m[11], m[15], 0.f, 0.f, 0.f, 1.f }
};
float t0, t1, t2, t3, t;
float* r0 = expmat[0], * r1 = expmat[1], * r2 = expmat[2], * r3 = expmat[3];
// Choose pivots and eliminate variables
if (fabs(r3[0]) > fabs(r2[0]))
{
std::swap(r3, r2);
}
if (fabs(r2[0]) > fabs(r1[0]))
{
std::swap(r2, r1);
}
if (fabs(r1[0]) > fabs(r0[0]))
{
std::swap(r1, r0);
}
if (r0[0] == 0)
{
return false;
}
t1 = r1[0] / r0[0];
t2 = r2[0] / r0[0];
t3 = r3[0] / r0[0];
t = r0[1];
r1[1] -= t1 * t;
r2[1] -= t2 * t;
r3[1] -= t3 * t;
t = r0[2];
r1[2] -= t1 * t;
r2[2] -= t2 * t;
r3[2] -= t3 * t;
t = r0[3];
r1[3] -= t1 * t;
r2[3] -= t2 * t;
r3[3] -= t3 * t;
t = r0[4];
if (t != 0.0)
{
r1[4] -= t1 * t;
r2[4] -= t2 * t;
r3[4] -= t3 * t;
}
t = r0[5];
if (t != 0.0)
{
r1[5] -= t1 * t;
r2[5] -= t2 * t;
r3[5] -= t3 * t;
}
t = r0[6];
if (t != 0.0)
{
r1[6] -= t1 * t;
r2[6] -= t2 * t;
r3[6] -= t3 * t;
}
t = r0[7];
if (t != 0.0)
{
r1[7] -= t1 * t;
r2[7] -= t2 * t;
r3[7] -= t3 * t;
}
if (fabs(r3[1]) > fabs(r2[1]))
{
std::swap(r3, r2);
}
if (fabs(r2[1]) > fabs(r1[1]))
{
std::swap(r2, r1);
}
if (r1[1] == 0)
{
return false;
}
t2 = r2[1] / r1[1];
t3 = r3[1] / r1[1];
r2[2] -= t2 * r1[2];
r3[2] -= t3 * r1[2];
r2[3] -= t2 * r1[3];
r3[3] -= t3 * r1[3];
t = r1[4];
if (0.0 != t)
{
r2[4] -= t2 * t;
r3[4] -= t3 * t;
}
t = r1[5];
if (0.0 != t)
{
r2[5] -= t2 * t;
r3[5] -= t3 * t;
}
t = r1[6];
if (0.0 != t)
{
r2[6] -= t2 * t;
r3[6] -= t3 * t;
}
t = r1[7];
if (0.0 != t)
{
r2[7] -= t2 * t;
r3[7] -= t3 * t;
}
if (fabs(r3[2]) > fabs(r2[2]))
{
std::swap(r3, r2);
}
if (r2[2] == 0)
{
return false;
}
t3 = r3[2] / r2[2];
r3[3] -= t3 * r2[3];
r3[4] -= t3 * r2[4];
r3[5] -= t3 * r2[5];
r3[6] -= t3 * r2[6];
r3[7] -= t3 * r2[7];
if (r3[3] == 0)
{
return false;
}
// Substitute back
t = 1.0f / r3[3];
r3[4] *= t;
r3[5] *= t;
r3[6] *= t;
r3[7] *= t; // Row 3
t2 = r2[3];
t = 1.0f / r2[2]; // Row 2
r2[4] = t * (r2[4] - r3[4] * t2);
r2[5] = t * (r2[5] - r3[5] * t2);
r2[6] = t * (r2[6] - r3[6] * t2);
r2[7] = t * (r2[7] - r3[7] * t2);
t1 = r1[3];
r1[4] -= r3[4] * t1;
r1[5] -= r3[5] * t1;
r1[6] -= r3[6] * t1;
r1[7] -= r3[7] * t1;
t0 = r0[3];
r0[4] -= r3[4] * t0;
r0[5] -= r3[5] * t0;
r0[6] -= r3[6] * t0;
r0[7] -= r3[7] * t0;
t1 = r1[2];
t = 1.0f / r1[1]; // Row 1
r1[4] = t * (r1[4] - r2[4] * t1);
r1[5] = t * (r1[5] - r2[5] * t1);
r1[6] = t * (r1[6] - r2[6] * t1);
r1[7] = t * (r1[7] - r2[7] * t1);
t0 = r0[2];
r0[4] -= r2[4] * t0;
r0[5] -= r2[5] * t0;
r0[6] -= r2[6] * t0, r0[7] -= r2[7] * t0;
t0 = r0[1];
t = 1.0f / r0[0]; // Row 0
r0[4] = t * (r0[4] - r1[4] * t0);
r0[5] = t * (r0[5] - r1[5] * t0);
r0[6] = t * (r0[6] - r1[6] * t0);
r0[7] = t * (r0[7] - r1[7] * t0);
out.m00 = r0[4];
out.m01 = r0[5];
out.m02 = r0[6];
out.m03 = r0[7];
out.m10 = r1[4];
out.m11 = r1[5];
out.m12 = r1[6];
out.m13 = r1[7];
out.m20 = r2[4];
out.m21 = r2[5];
out.m22 = r2[6];
out.m23 = r2[7];
out.m30 = r3[4];
out.m31 = r3[5];
out.m32 = r3[6];
out.m33 = r3[7];
return true;
}
static int sUnProject(float winx, float winy, float winz, const float model[16], const float proj[16], const int viewport[4], float* objx, float* objy, float* objz)
{
Vec4 vIn;
vIn.x = (winx - viewport[0]) * 2 / viewport[2] - 1.0f;
vIn.y = (winy - viewport[1]) * 2 / viewport[3] - 1.0f;
vIn.z = winz;//2.0f * winz - 1.0f;
vIn.w = 1.0;
float m1[16];
for (int i = 0; i < 4; i++)
{
float ai0 = proj[i], ai1 = proj[4 + i], ai2 = proj[8 + i], ai3 = proj[12 + i];
m1[i] = ai0 * model[0] + ai1 * model[1] + ai2 * model[2] + ai3 * model[3];
m1[4 + i] = ai0 * model[4] + ai1 * model[5] + ai2 * model[6] + ai3 * model[7];
m1[8 + i] = ai0 * model[8] + ai1 * model[9] + ai2 * model[10] + ai3 * model[11];
m1[12 + i] = ai0 * model[12] + ai1 * model[13] + ai2 * model[14] + ai3 * model[15];
}
Matrix44 m;
InvertMatrixPrecise(m, m1);
Vec4 vOut = m * vIn;
if (vOut.w == 0.0)
{
return false;
}
*objx = vOut.x / vOut.w;
*objy = vOut.y / vOut.w;
*objz = vOut.z / vOut.w;
return true;
}
int CAtomShimRenderer::UnProject(float sx, float sy, float sz,
float* px, float* py, float* pz,
const float modelMatrix[16],
const float projMatrix[16],
const int viewport[4])
{
return sUnProject(sx, sy, sz, modelMatrix, projMatrix, viewport, px, py, pz);
}
//////////////////////////////////////////////////////////////////////
int CAtomShimRenderer::UnProjectFromScreen(float sx, float sy, float sz,
float* px, float* py, float* pz)
{
float modelMatrix[16];
float projMatrix[16];
int viewport[4];
const int nThreadID = m_pRT->GetThreadList();
if (m_RP.m_TI[nThreadID].m_PersFlags & RBPF_REVERSE_DEPTH)
{
sz = 1.0f - sz;
}
GetModelViewMatrix(modelMatrix);
GetProjectionMatrix(projMatrix);
GetViewport(&viewport[0], &viewport[1], &viewport[2], &viewport[3]);
return sUnProject(sx, sy, sz, modelMatrix, projMatrix, viewport, px, py, pz);
}
//////////////////////////////////////////////////////////////////////
bool CAtomShimRenderer::ScreenShot([[maybe_unused]] const char* filename, [[maybe_unused]] int width)
{
return true;
}
int CAtomShimRenderer::ScreenToTexture([[maybe_unused]] int nTexID)
{
return 0;
}
void CAtomShimRenderer::ResetToDefault()
{
}
///////////////////////////////////////////
void CAtomShimRenderer::SetMaterialColor([[maybe_unused]] float r, [[maybe_unused]] float g, [[maybe_unused]] float b, [[maybe_unused]] float a)
{
}
//////////////////////////////////////////////////////////////////////
void CAtomShimRenderer::ClearTargetsImmediately([[maybe_unused]] uint32 nFlags) {}
void CAtomShimRenderer::ClearTargetsImmediately([[maybe_unused]] uint32 nFlags, [[maybe_unused]] const ColorF& Colors, [[maybe_unused]] float fDepth) {}
void CAtomShimRenderer::ClearTargetsImmediately([[maybe_unused]] uint32 nFlags, [[maybe_unused]] const ColorF& Colors) {}
void CAtomShimRenderer::ClearTargetsImmediately([[maybe_unused]] uint32 nFlags, [[maybe_unused]] float fDepth) {}
void CAtomShimRenderer::ClearTargetsLater([[maybe_unused]] uint32 nFlags) {}
void CAtomShimRenderer::ClearTargetsLater([[maybe_unused]] uint32 nFlags, [[maybe_unused]] const ColorF& Colors, [[maybe_unused]] float fDepth) {}
void CAtomShimRenderer::ClearTargetsLater([[maybe_unused]] uint32 nFlags, [[maybe_unused]] const ColorF& Colors) {}
void CAtomShimRenderer::ClearTargetsLater([[maybe_unused]] uint32 nFlags, [[maybe_unused]] float fDepth) {}
void CAtomShimRenderer::ReadFrameBuffer([[maybe_unused]] unsigned char* pRGB, [[maybe_unused]] int nImageX, [[maybe_unused]] int nSizeX, [[maybe_unused]] int nSizeY, [[maybe_unused]] ERB_Type eRBType, [[maybe_unused]] bool bRGBA, [[maybe_unused]] int nScaledX, [[maybe_unused]] int nScaledY)
{
}
void CAtomShimRenderer::ReadFrameBufferFast([[maybe_unused]] uint32* pDstARGBA8, [[maybe_unused]] int dstWidth, [[maybe_unused]] int dstHeight, [[maybe_unused]] bool BGRA)
{
}
bool CAtomShimRenderer::CaptureFrameBufferFast([[maybe_unused]] unsigned char* pDstRGBA8, [[maybe_unused]] int destinationWidth, [[maybe_unused]] int destinationHeight)
{
return false;
}
bool CAtomShimRenderer::CopyFrameBufferFast([[maybe_unused]] unsigned char* pDstRGBA8, [[maybe_unused]] int destinationWidth, [[maybe_unused]] int destinationHeight)
{
return false;
}
bool CAtomShimRenderer::InitCaptureFrameBufferFast([[maybe_unused]] uint32 bufferWidth, [[maybe_unused]] uint32 bufferHeight)
{
return(false);
}
void CAtomShimRenderer::CloseCaptureFrameBufferFast(void)
{
}
bool CAtomShimRenderer::RegisterCaptureFrame([[maybe_unused]] ICaptureFrameListener* pCapture)
{
return(false);
}
bool CAtomShimRenderer::UnRegisterCaptureFrame([[maybe_unused]] ICaptureFrameListener* pCapture)
{
return(false);
}
void CAtomShimRenderer::CaptureFrameBufferCallBack(void)
{
}
void CAtomShimRenderer::SetFogColor([[maybe_unused]] const ColorF& color)
{
}
void CAtomShimRenderer::DrawQuad([[maybe_unused]] float dy, [[maybe_unused]] float dx, [[maybe_unused]] float dz, [[maybe_unused]] float x, [[maybe_unused]] float y, [[maybe_unused]] float z)
{
}
//////////////////////////////////////////////////////////////////////
int CAtomShimRenderer::CreateRenderTarget([[maybe_unused]] const char* name, [[maybe_unused]] int nWidth, [[maybe_unused]] int nHeight, [[maybe_unused]] const ColorF& cClear, [[maybe_unused]] ETEX_Format eTF)
{
return 0;
}
bool CAtomShimRenderer::ResizeRenderTarget([[maybe_unused]] int nHandle, [[maybe_unused]] int nWidth, [[maybe_unused]] int nHeight)
{
return true;
}
bool CAtomShimRenderer::DestroyRenderTarget([[maybe_unused]] int nHandle)
{
return true;
}
bool CAtomShimRenderer::SetRenderTarget([[maybe_unused]] int nHandle, [[maybe_unused]] SDepthTexture* pDepthSurf)
{
return true;
}
SDepthTexture* CAtomShimRenderer::CreateDepthSurface([[maybe_unused]] int nWidth, [[maybe_unused]] int nHeight, [[maybe_unused]] bool shaderResourceView)
{
return nullptr;
}
void CAtomShimRenderer::DestroyDepthSurface([[maybe_unused]] SDepthTexture* pDepthSurf)
{
}
void CAtomShimRenderer::WaitForParticleBuffer([[maybe_unused]] threadID nThreadId)
{
}
int CAtomShimRenderer::GetOcclusionBuffer([[maybe_unused]] uint16* pOutOcclBuffer, [[maybe_unused]] Matrix44* pmCamBuffe)
{
return 0;
}
IColorGradingController* CAtomShimRenderer::GetIColorGradingController()
{
return m_pAtomShimColorGradingController;
}
IStereoRenderer* CAtomShimRenderer::GetIStereoRenderer()
{
return m_pAtomShimStereoRenderer;
}
ITexture* CAtomShimRenderer::Create2DTexture([[maybe_unused]] const char* name, [[maybe_unused]] int width, [[maybe_unused]] int height, [[maybe_unused]] int numMips, [[maybe_unused]] int flags, [[maybe_unused]] unsigned char* data, [[maybe_unused]] ETEX_Format format)
{
return nullptr;
}
//=========================================================================================
ILog* iLog;
IConsole* iConsole;
ITimer* iTimer;
ISystem* iSystem;
StaticInstance<CAtomShimRenderer> g_nullRenderer;
extern "C" DLL_EXPORT IRenderer * CreateCryRenderInterface(ISystem * pSystem)
{
ModuleInitISystem(pSystem, "CryRenderer");
gbRgb = false;
iConsole = gEnv->pConsole;
iLog = gEnv->pLog;
iTimer = gEnv->pTimer;
iSystem = gEnv->pSystem;
CRenderer* rd = g_nullRenderer;
if (rd)
{
rd->InitRenderer();
}
std::random_device randDev;
srand(static_cast<int>(randDev()));
return rd;
}
class CEngineModule_CryRenderer
: public IEngineModule
{
CRYINTERFACE_SIMPLE(IEngineModule)
CRYGENERATE_SINGLETONCLASS(CEngineModule_CryRenderer, "EngineModule_CryRenderer", 0x540c91a7338e41d3, 0xaceeac9d55614450)
virtual const char* GetName() const {
return "CryRenderer";
}
virtual const char* GetCategory() const {return "CryEngine"; }
virtual bool Initialize(SSystemGlobalEnvironment& env, [[maybe_unused]] const SSystemInitParams& initParams)
{
ISystem* pSystem = env.pSystem;
env.pRenderer = CreateCryRenderInterface(pSystem);
return env.pRenderer != 0;
}
};
CRYREGISTER_SINGLETON_CLASS(CEngineModule_CryRenderer)
CEngineModule_CryRenderer::CEngineModule_CryRenderer()
{
};
CEngineModule_CryRenderer::~CEngineModule_CryRenderer()
{
};
void COcclusionQuery::Create()
{
}
void COcclusionQuery::Release()
{
}
void COcclusionQuery::BeginQuery()
{
}
void COcclusionQuery::EndQuery()
{
}
uint32 COcclusionQuery::GetVisibleSamples([[maybe_unused]] bool bAsynchronous)
{
return 0;
}
/*static*/ FurBendData& FurBendData::Get()
{
static FurBendData s_instance;
return s_instance;
}
void FurBendData::InsertNewElements()
{
}
void FurBendData::FreeData()
{
}
void FurBendData::OnBeginFrame()
{
}
TArray<SRenderLight>* CRenderer::EF_GetDeferredLights([[maybe_unused]] const SRenderingPassInfo& passInfo, [[maybe_unused]] const eDeferredLightType eLightType)
{
static TArray<SRenderLight> lights;
return &lights;
}
SRenderLight* CRenderer::EF_GetDeferredLightByID([[maybe_unused]] const uint16 nLightID, [[maybe_unused]] const eDeferredLightType eLightType)
{
return nullptr;
}
void CRenderer::BeginSpawningGeneratingRendItemJobs([[maybe_unused]] int nThreadID)
{
}
void CRenderer::BeginSpawningShadowGeneratingRendItemJobs([[maybe_unused]] int nThreadID)
{
}
void CRenderer::EndSpawningGeneratingRendItemJobs()
{
}
void CAtomShimRenderer::PrecacheResources()
{
}
bool CAtomShimRenderer::EF_PrecacheResource([[maybe_unused]] SShaderItem* pSI, [[maybe_unused]] float fMipFactorSI, [[maybe_unused]] float fTimeToReady, [[maybe_unused]] int Flags, [[maybe_unused]] int nUpdateId, [[maybe_unused]] int nCounter)
{
return true;
}
ITexture* CAtomShimRenderer::EF_CreateCompositeTexture([[maybe_unused]] int type, [[maybe_unused]] const char* szName, [[maybe_unused]] int nWidth, [[maybe_unused]] int nHeight, [[maybe_unused]] int nDepth, [[maybe_unused]] int nMips, [[maybe_unused]] int nFlags, [[maybe_unused]] ETEX_Format eTF, [[maybe_unused]] const STexComposition* pCompositions, [[maybe_unused]] size_t nCompositions, [[maybe_unused]] int8 nPriority)
{
return CTextureManager::Instance()->GetNoTexture();
}
void CAtomShimRenderer::FX_ClearTarget([[maybe_unused]] ITexture* pTex)
{
}
void CAtomShimRenderer::FX_ClearTarget([[maybe_unused]] SDepthTexture* pTex)
{
}
bool CAtomShimRenderer::FX_SetRenderTarget([[maybe_unused]] int nTarget, [[maybe_unused]] void* pTargetSurf, [[maybe_unused]] SDepthTexture* pDepthTarget, [[maybe_unused]] uint32 nTileCount)
{
return true;
}
bool CAtomShimRenderer::FX_PushRenderTarget([[maybe_unused]] int nTarget, [[maybe_unused]] void* pTargetSurf, [[maybe_unused]] SDepthTexture* pDepthTarget, [[maybe_unused]] uint32 nTileCount)
{
return true;
}
bool CAtomShimRenderer::FX_SetRenderTarget([[maybe_unused]] int nTarget, [[maybe_unused]] CTexture* pTarget, [[maybe_unused]] SDepthTexture* pDepthTarget, [[maybe_unused]] bool bPush, [[maybe_unused]] int nCMSide, [[maybe_unused]] bool bScreenVP, [[maybe_unused]] uint32 nTileCount)
{
return true;
}
bool CAtomShimRenderer::FX_PushRenderTarget([[maybe_unused]] int nTarget, [[maybe_unused]] CTexture* pTarget, [[maybe_unused]] SDepthTexture* pDepthTarget, [[maybe_unused]] int nCMSide, [[maybe_unused]] bool bScreenVP, [[maybe_unused]] uint32 nTileCount)
{
return true;
}
bool CAtomShimRenderer::FX_RestoreRenderTarget([[maybe_unused]] int nTarget)
{
return true;
}
bool CAtomShimRenderer::FX_PopRenderTarget([[maybe_unused]] int nTarget)
{
return true;
}
IDynTexture* CAtomShimRenderer::CreateDynTexture2([[maybe_unused]] uint32 nWidth, [[maybe_unused]] uint32 nHeight, [[maybe_unused]] uint32 nTexFlags, [[maybe_unused]] const char* szSource, [[maybe_unused]] ETexPool eTexPool)
{
return nullptr;
}
void CAtomShimRenderer::InitSystemResources([[maybe_unused]] int nFlags)
{
// This is an override of the implementation in CRenderer and is significantly cut down for the shim.
if (!m_bSystemResourcesInit || m_bDeviceLost == 2)
{
CTextureManager::Instance()->Init();
m_bSystemResourcesInit = 1;
}
}
void CAtomShimRenderer::SetTexture(int tnum)
{
SetTexture(tnum, 0);
}
void CAtomShimRenderer::SetTexture(int tnum, int nUnit)
{
SetTextureForUnit(nUnit, tnum);
}
void CAtomShimRenderer::SetState([[maybe_unused]] int State, [[maybe_unused]] int AlphaRef)
{
// [GFX TODO] would need to implement this for LyShine mask support and blend mode support
}
void CAtomShimRenderer::SetTextureForUnit(int unit, int textureId)
{
AZ_Assert(unit >= 0 && unit < 32, "Invalid texture unit");
AtomShimTexture* atomTexture = CastITextureToAtomShimTexture(EF_GetTextureByID(textureId));
m_currentTextureForUnit[unit] = atomTexture;
m_clampFlagPerTextureUnit[unit] = (atomTexture->GetFlags() & FT_STATE_CLAMP) ? true : false;
}
const AZ::Transform& CAtomShimRenderer::GetActiveCameraTransform()
{
return m_cameraTransform;
}
const Camera::Configuration& CAtomShimRenderer::GetActiveCameraConfiguration()
{
return m_cameraConfiguration;
}
void CAtomShimRenderer::CacheCameraTransform(const CCamera& camera)
{
m_cameraTransform = LYTransformToAZTransform(camera.GetMatrix());
}
void CAtomShimRenderer::CacheCameraConfiguration(const CCamera& camera)
{
Camera::Configuration& config = m_cameraConfiguration;
config.m_fovRadians = camera.GetFov();
config.m_nearClipDistance = camera.GetNearPlane();
config.m_farClipDistance = camera.GetFarPlane();
config.m_frustumHeight = config.m_farClipDistance * tanf(config.m_fovRadians / 2) * 2;
config.m_frustumWidth = config.m_frustumHeight * camera.GetViewSurfaceX() / camera.GetViewSurfaceZ();
}
void CAtomShimRenderer::DrawStringU(
[[maybe_unused]] IFFont_RenderProxy* pFont, [[maybe_unused]] float x, [[maybe_unused]] float y, [[maybe_unused]] float z,
[[maybe_unused]] const char* pStr, [[maybe_unused]] const bool asciiMultiLine, [[maybe_unused]] const STextDrawContext& ctx) const
{
// RenderCallback disabled, ICryFont has been directly implemented on Atom by Gems/AtomLyIntegration/AtomFont.
}
void CAtomShimRenderer::DrawDynVB(SVF_P3F_C4B_T2F* pBuf, uint16* pInds, int nVerts, int nInds, const PublicRenderPrimitiveType nPrimType)
{
using namespace AZ;
// if nothing to draw then return
if (!pBuf || !nVerts || (pInds && !nInds) || (nInds && !pInds))
{
return;
}
// get view proj materix
Matrix44A matView, matProj;
GetModelViewMatrix(matView.GetData());
GetProjectionMatrix(matProj.GetData());
Matrix44A matViewProj = matView * matProj;
Matrix4x4 azMatViewProj = Matrix4x4::CreateFromColumnMajorFloat16(matViewProj.GetData());
bool isClamp = m_clampFlagPerTextureUnit[0];
m_dynamicDraw->SetShaderVariant(isClamp? m_shaderVariantClamp : m_shaderVariantWrap);
Data::Instance<RPI::ShaderResourceGroup> drawSrg = m_dynamicDraw->NewDrawSrg();
drawSrg->SetConstant(m_viewProjInputIndex, azMatViewProj);
AtomShimTexture* atomTexture = m_currentTextureForUnit[0];
drawSrg->SetImageView(m_imageInputIndex, atomTexture->m_imageView.get());
drawSrg->Compile();
RHI::PrimitiveTopology primitiveType = RHI::PrimitiveTopology::TriangleList;
switch (nPrimType)
{
case prtTriangleList:
primitiveType = RHI::PrimitiveTopology::TriangleList;
break;
case prtTriangleStrip:
primitiveType = RHI::PrimitiveTopology::TriangleStrip;
break;
case prtLineList:
primitiveType = RHI::PrimitiveTopology::LineList;
break;
case prtLineStrip:
primitiveType = RHI::PrimitiveTopology::LineStrip;
break;
}
m_dynamicDraw->SetPrimitiveType(primitiveType);
if (pInds)
{
m_dynamicDraw->DrawIndexed(pBuf, nVerts, pInds, nInds, RHI::IndexFormat::Uint16, drawSrg);
}
else
{
m_dynamicDraw->DrawLinear(pBuf, nVerts, drawSrg);
}
}
void CAtomShimRenderer::DrawDynUiPrimitiveList(
[[maybe_unused]] DynUiPrimitiveList& primitives, [[maybe_unused]] int totalNumVertices, [[maybe_unused]] int totalNumIndices)
{
// This function was only used by LyShine and LyShine is moving to Atom implementation.
return;
}
void CAtomShimRenderer::Set2DMode(uint32 orthoWidth, uint32 orthoHeight, TransformationMatrices& backupMatrices, float znear, float zfar)
{
Set2DModeNonZeroTopLeft(0.0f, 0.0f, static_cast<float>(orthoWidth), static_cast<float>(orthoHeight), backupMatrices, znear, zfar);
}
void CAtomShimRenderer::Unset2DMode(const TransformationMatrices& restoringMatrices)
{
int nThreadID = m_pRT->GetThreadList();
#ifdef _DEBUG
// Check that we are already in 2D mode on this thread and decrement the counter used for this check.
AZ_Assert(s_isIn2DMode[nThreadID]-- > 0, "Calls to Set2DMode and Unset2DMode appear mismatched");
#endif
m_RP.m_TI[nThreadID].m_matView = restoringMatrices.m_viewMatrix;
m_RP.m_TI[nThreadID].m_matProj = restoringMatrices.m_projectMatrix;
// The legacy renderer supports nested Set2dMode/Unset2dMode so we use a counter to support that also.
m_isIn2dModeCounter--;
if (m_isIn2dModeCounter > 0)
{
// We're still in 2d mode, so set the viewProjOverride to the current matrix
// For 2d drawing, the view matrix is an identity matrix, so viewProj == proj
AZ::Matrix4x4 viewProj = AZ::Matrix4x4::CreateFromColumnMajorFloat16(m_RP.m_TI[nThreadID].m_matProj.GetData());
m_pAtomShimRenderAuxGeom->SetViewProjOverride(viewProj);
}
else
{
m_pAtomShimRenderAuxGeom->UnsetViewProjOverride();
}
}
void CAtomShimRenderer::Set2DModeNonZeroTopLeft(
float orthoLeft, float orthoTop, float orthoWidth, float orthoHeight, TransformationMatrices& backupMatrices, float znear, float zfar)
{
int nThreadID = m_pRT->GetThreadList();
#ifdef _DEBUG
// Increment the counter used to check that Set2DMode and Unset2DMode are balanced.
// It should never be negative before the increment.
AZ_Assert(s_isIn2DMode[nThreadID]++ >= 0, "Calls to Set2DMode and Unset2DMode appear mismatched");
#endif
backupMatrices.m_projectMatrix = m_RP.m_TI[nThreadID].m_matProj;
// Move the zfar a bit away from the znear if they're the same.
if (AZ::IsClose(znear, zfar, .001f))
{
zfar += .01f;
}
float left = orthoLeft;
float right = left + orthoWidth;
float top = orthoTop;
float bottom = top + orthoHeight;
mathMatrixOrthoOffCenterLH(&m_RP.m_TI[nThreadID].m_matProj, left, right, bottom, top, znear, zfar);
if (m_RP.m_TI[nThreadID].m_PersFlags & RBPF_REVERSE_DEPTH)
{
// [GFX TODO] [ATOM-661] may need to reverse the depth here (though for 2D it may not be necessary)
}
backupMatrices.m_viewMatrix = m_RP.m_TI[nThreadID].m_matView;
m_RP.m_TI[nThreadID].m_matView.SetIdentity();
m_isIn2dModeCounter++;
// For 2d drawing, the view matrix is an identity matrix, so viewProj == proj
AZ::Matrix4x4 viewProj = AZ::Matrix4x4::CreateFromColumnMajorFloat16(m_RP.m_TI[nThreadID].m_matProj.GetData());
m_pAtomShimRenderAuxGeom->SetViewProjOverride(viewProj);
}
void CAtomShimRenderer::SetColorOp(
[[maybe_unused]] byte eCo, [[maybe_unused]] byte eAo, [[maybe_unused]] byte eCa, [[maybe_unused]] byte eAa)
{
// this is only used by LY ImGui gem
}