metaforce/Runtime/Graphics/CGraphics.cpp

384 lines
12 KiB
C++
Raw Normal View History

2016-03-04 15:04:53 -08:00
#include "Graphics/CGraphics.hpp"
2016-03-14 21:55:57 -07:00
#include "Graphics/CLight.hpp"
2016-03-04 15:04:53 -08:00
#include "zeus/Math.hpp"
2016-03-30 23:18:56 -07:00
#include "CTimeProvider.hpp"
2016-02-11 18:36:34 -08:00
2016-02-16 19:42:27 -08:00
#undef near
#undef far
2016-03-04 15:04:53 -08:00
namespace urde
2016-02-11 18:36:34 -08:00
{
2016-02-13 19:42:36 -08:00
CGraphics::CProjectionState CGraphics::g_Proj;
float CGraphics::g_ProjAspect = 1.f;
2016-02-11 18:36:34 -08:00
u32 CGraphics::g_NumLightsActive = 0;
2016-03-06 19:12:32 -08:00
u32 CGraphics::g_NumBreakpointsWaiting = 0;
u32 CGraphics::g_FlippingState;
bool CGraphics::g_LastFrameUsedAbove = false;
bool CGraphics::g_InterruptLastFrameUsedAbove = false;
2016-03-14 21:55:57 -07:00
ERglLightBits CGraphics::g_LightActive = ERglLightBits::None;
ERglLightBits CGraphics::g_LightsWereOn = ERglLightBits::None;
2016-03-04 15:04:53 -08:00
zeus::CTransform CGraphics::g_GXModelView;
2016-03-30 23:18:56 -07:00
zeus::CTransform CGraphics::g_GXModelViewInvXpose;
2016-03-04 15:04:53 -08:00
zeus::CTransform CGraphics::g_GXModelMatrix;
zeus::CTransform CGraphics::g_ViewMatrix;
zeus::CVector3f CGraphics::g_ViewPoint;
zeus::CTransform CGraphics::g_GXViewPointMatrix;
zeus::CTransform CGraphics::g_CameraMatrix;
zeus::CVector2i CGraphics::g_ViewportResolution;
zeus::CVector2i CGraphics::g_ViewportResolutionHalf;
2016-02-16 00:52:22 -08:00
int CGraphics::g_ViewportSamples = 1;
2016-02-13 19:42:36 -08:00
bool CGraphics::g_IsGXModelMatrixIdentity;
2016-02-11 18:36:34 -08:00
void CGraphics::DisableAllLights()
{
g_NumLightsActive = 0;
2016-03-14 21:55:57 -07:00
g_LightActive = ERglLightBits::None;
2016-02-11 18:36:34 -08:00
// TODO: turn lights off for real
}
2016-03-14 21:55:57 -07:00
void CGraphics::LoadLight(ERglLight light, const CLight& info)
{
// TODO: load light for real
}
2016-02-11 18:36:34 -08:00
void CGraphics::EnableLight(ERglLight light)
{
2016-03-14 21:55:57 -07:00
ERglLightBits lightBit = ERglLightBits(1 << int(light));
if ((lightBit & g_LightActive) == ERglLightBits::None)
2016-02-11 18:36:34 -08:00
{
2016-03-14 21:55:57 -07:00
g_LightActive |= lightBit;
2016-02-11 18:36:34 -08:00
++g_NumLightsActive;
// TODO: turn light on for real
}
g_LightsWereOn = g_LightActive;
}
2016-03-14 21:55:57 -07:00
void CGraphics::SetLightState(ERglLightBits lightState)
2016-02-11 18:36:34 -08:00
{
// TODO: set state for real
g_LightActive = lightState;
2016-03-04 15:04:53 -08:00
g_NumLightsActive = zeus::PopCount(lightState);
2016-02-11 18:36:34 -08:00
}
2016-03-14 21:55:57 -07:00
void CGraphics::SetAmbientColor(const zeus::CColor& col)
{
// TODO: set for real
}
2016-02-13 19:42:36 -08:00
void CGraphics::SetDepthWriteMode(bool test, ERglEnum comp, bool write)
2016-02-12 16:57:09 -08:00
{
}
void CGraphics::SetBlendMode(ERglBlendMode, ERglBlendFactor, ERglBlendFactor, ERglLogicOp)
{
}
void CGraphics::SetCullMode(ERglCullMode)
{
}
2016-03-06 19:12:32 -08:00
void CGraphics::EndScene()
{
/* Spinwait until g_NumBreakpointsWaiting is 0 */
/* ++g_NumBreakpointsWaiting; */
/* GXCopyDisp to g_CurrenFrameBuf with clear enabled */
/* Register next breakpoint with GP FIFO */
/* Yup, GX had fences long before D3D12 and Vulkan
* (same functionality implemented in boo's execute method) */
/* This usually comes from VI register during interrupt;
* we don't care in the era of progressive-scan dominance,
* so simulate field-flipping with XOR instead */
g_InterruptLastFrameUsedAbove ^= 1;
g_LastFrameUsedAbove = g_InterruptLastFrameUsedAbove;
2016-03-06 19:12:32 -08:00
}
2016-02-12 16:57:09 -08:00
void CGraphics::SetAlphaCompare(ERglAlphaFunc comp0, u8 ref0, ERglAlphaOp op, ERglAlphaFunc comp1, u8 ref1)
{
}
2016-03-04 15:04:53 -08:00
void CGraphics::SetViewPointMatrix(const zeus::CTransform& xf)
2016-02-13 19:42:36 -08:00
{
g_ViewMatrix = xf;
g_ViewPoint = xf.m_origin;
2016-03-04 15:04:53 -08:00
zeus::CMatrix3f tmp(xf.m_basis[0], xf.m_basis[2], -xf.m_basis[1]);
g_GXViewPointMatrix = zeus::CTransform(tmp.transposed());
2016-02-13 19:42:36 -08:00
SetViewMatrix();
}
void CGraphics::SetViewMatrix()
{
2016-03-04 15:04:53 -08:00
g_CameraMatrix = g_GXViewPointMatrix * zeus::CTransform::Translate(-g_ViewPoint);
2016-02-13 19:42:36 -08:00
if (g_IsGXModelMatrixIdentity)
g_GXModelView = g_CameraMatrix;
else
g_GXModelView = g_CameraMatrix * g_GXModelMatrix;
/* Load position matrix */
/* Inverse-transpose */
2016-03-30 23:18:56 -07:00
g_GXModelViewInvXpose = g_GXModelView.inverse();
2016-04-01 17:07:07 -07:00
g_GXModelViewInvXpose.m_origin.zeroOut();
2016-03-30 23:18:56 -07:00
g_GXModelViewInvXpose.m_basis.transpose();
2016-02-13 19:42:36 -08:00
/* Load normal matrix */
}
2016-03-04 15:04:53 -08:00
void CGraphics::SetModelMatrix(const zeus::CTransform& xf)
2016-02-12 16:57:09 -08:00
{
2016-02-13 19:42:36 -08:00
g_IsGXModelMatrixIdentity = false;
g_GXModelMatrix = xf;
SetViewMatrix();
}
2016-03-15 20:37:51 -07:00
zeus::CMatrix4f CGraphics::CalculatePerspectiveMatrix(float fovy, float aspect,
2016-04-02 22:25:34 -07:00
float near, float far,
bool forRenderer)
2016-03-15 20:37:51 -07:00
{
CProjectionState st;
float tfov = std::tan(zeus::degToRad(fovy * 0.5f));
st.x14_near = near;
st.x18_far = far;
st.xc_top = near * tfov;
st.x10_bottom = -st.xc_top;
st.x8_right = aspect * near * tfov;
st.x4_left = -st.x8_right;
float rml = st.x8_right - st.x4_left;
float rpl = st.x8_right + st.x4_left;
float tmb = st.xc_top - st.x10_bottom;
float tpb = st.xc_top + st.x10_bottom;
float fpn = st.x18_far + st.x14_near;
2016-04-02 22:25:34 -07:00
float fmn = st.x18_far - st.x14_near;
if (!forRenderer)
{
return zeus::CMatrix4f(2.f * st.x14_near / rml, 0.f, rpl / rml, 0.f,
0.f, 2.f * st.x14_near / tmb, tpb / tmb, 0.f,
0.f, 0.f, -fpn / fmn, -2.f * st.x18_far * st.x14_near / fmn,
0.f, 0.f, -1.f, 0.f);
}
switch (g_BooPlatform)
{
case boo::IGraphicsDataFactory::Platform::OGL:
default:
{
return zeus::CMatrix4f(2.f * st.x14_near / rml, 0.f, rpl / rml, 0.f,
0.f, 2.f * st.x14_near / tmb, tpb / tmb, 0.f,
0.f, 0.f, -fpn / fmn, -2.f * st.x18_far * st.x14_near / fmn,
0.f, 0.f, -1.f, 0.f);
}
case boo::IGraphicsDataFactory::Platform::D3D11:
case boo::IGraphicsDataFactory::Platform::D3D12:
2016-04-02 23:19:33 -07:00
case boo::IGraphicsDataFactory::Platform::Metal:
2016-04-02 22:25:34 -07:00
{
zeus::CMatrix4f mat2(2.f * st.x14_near / rml, 0.f, rpl / rml, 0.f,
0.f, 2.f * st.x14_near / tmb, tpb / tmb, 0.f,
0.f, 0.f, st.x18_far / fmn, st.x14_near * st.x18_far / fmn,
0.f, 0.f, -1.f, 0.f);
static const zeus::CMatrix4f PlusOneZ(1.f, 0.f, 0.f, 0.f,
0.f, 1.f, 0.f, 0.f,
0.f, 0.f, 1.f, 1.f,
0.f, 0.f, 0.f, 1.f);
return PlusOneZ * mat2;
}
}
2016-03-15 20:37:51 -07:00
}
2016-04-02 22:25:34 -07:00
zeus::CMatrix4f CGraphics::GetPerspectiveProjectionMatrix(bool forRenderer)
2016-02-13 19:42:36 -08:00
{
float rml = g_Proj.x8_right - g_Proj.x4_left;
float rpl = g_Proj.x8_right + g_Proj.x4_left;
float tmb = g_Proj.xc_top - g_Proj.x10_bottom;
float tpb = g_Proj.xc_top + g_Proj.x10_bottom;
float fpn = g_Proj.x18_far + g_Proj.x14_near;
2016-04-02 22:25:34 -07:00
float fmn = g_Proj.x18_far - g_Proj.x14_near;
if (!forRenderer)
{
return zeus::CMatrix4f(2.f * g_Proj.x14_near / rml, 0.f, rpl / rml, 0.f,
0.f, 2.f * g_Proj.x14_near / tmb, tpb / tmb, 0.f,
0.f, 0.f, -fpn / fmn, -2.f * g_Proj.x18_far * g_Proj.x14_near / fmn,
0.f, 0.f, -1.f, 0.f);
}
switch (g_BooPlatform)
{
case boo::IGraphicsDataFactory::Platform::OGL:
default:
{
return zeus::CMatrix4f(2.f * g_Proj.x14_near / rml, 0.f, rpl / rml, 0.f,
0.f, 2.f * g_Proj.x14_near / tmb, tpb / tmb, 0.f,
0.f, 0.f, -fpn / fmn, -2.f * g_Proj.x18_far * g_Proj.x14_near / fmn,
0.f, 0.f, -1.f, 0.f);
}
case boo::IGraphicsDataFactory::Platform::D3D11:
case boo::IGraphicsDataFactory::Platform::D3D12:
2016-04-02 23:19:33 -07:00
case boo::IGraphicsDataFactory::Platform::Metal:
2016-04-02 22:25:34 -07:00
{
zeus::CMatrix4f mat2(2.f * g_Proj.x14_near / rml, 0.f, rpl / rml, 0.f,
0.f, 2.f * g_Proj.x14_near / tmb, tpb / tmb, 0.f,
0.f, 0.f, g_Proj.x18_far / fmn, g_Proj.x14_near * g_Proj.x18_far / fmn,
0.f, 0.f, -1.f, 0.f);
static const zeus::CMatrix4f PlusOneZ(1.f, 0.f, 0.f, 0.f,
0.f, 1.f, 0.f, 0.f,
0.f, 0.f, 1.f, 1.f,
0.f, 0.f, 0.f, 1.f);
return PlusOneZ * mat2;
}
}
2016-02-13 19:42:36 -08:00
}
const CGraphics::CProjectionState& CGraphics::GetProjectionState()
{
return g_Proj;
}
void CGraphics::SetProjectionState(const CGraphics::CProjectionState& proj)
{
g_Proj = proj;
FlushProjection();
}
void CGraphics::SetPerspective(float fovy, float aspect, float near, float far)
{
g_ProjAspect = aspect;
2016-03-04 15:04:53 -08:00
float tfov = std::tan(zeus::degToRad(fovy * 0.5f));
2016-02-13 19:42:36 -08:00
g_Proj.x0_persp = true;
g_Proj.x14_near = near;
g_Proj.x18_far = far;
g_Proj.xc_top = near * tfov;
g_Proj.x10_bottom = -g_Proj.xc_top;
g_Proj.x8_right = aspect * near * tfov;
g_Proj.x4_left = -g_Proj.x8_right;
2016-03-15 20:37:51 -07:00
FlushProjection();
}
void CGraphics::SetOrtho(float left, float right,
float top, float bottom,
float znear, float zfar)
{
g_Proj.x0_persp = false;
g_Proj.x4_left = left;
g_Proj.x8_right = right;
g_Proj.xc_top = top;
g_Proj.x10_bottom = bottom;
g_Proj.x14_near = znear;
g_Proj.x18_far = zfar;
FlushProjection();
2016-02-13 19:42:36 -08:00
}
void CGraphics::FlushProjection()
{
if (g_Proj.x0_persp)
{
// Convert and load persp
}
else
{
// Convert and load ortho
}
}
2016-03-04 15:04:53 -08:00
zeus::CVector2i CGraphics::ProjectPoint(const zeus::CVector3f& point)
2016-02-13 19:42:36 -08:00
{
2016-04-02 22:25:34 -07:00
zeus::CVector3f projPt = GetPerspectiveProjectionMatrix(false).multiplyOneOverW(point);
2016-02-13 19:42:36 -08:00
return {int(projPt.x * g_ViewportResolutionHalf.x) + g_ViewportResolutionHalf.x,
2016-02-24 18:55:38 -08:00
g_ViewportResolution.y - (int(projPt.y * g_ViewportResolutionHalf.y) + g_ViewportResolutionHalf.y)};
2016-02-13 19:42:36 -08:00
}
2016-03-04 15:04:53 -08:00
SClipScreenRect CGraphics::ClipScreenRectFromMS(const zeus::CVector3f& p1,
const zeus::CVector3f& p2)
2016-02-13 19:42:36 -08:00
{
2016-03-04 15:04:53 -08:00
zeus::CVector3f xf1 = g_GXModelView * p1;
zeus::CVector3f xf2 = g_GXModelView * p2;
return ClipScreenRectFromVS(xf1, xf2);
2016-02-13 19:42:36 -08:00
}
2016-03-04 15:04:53 -08:00
SClipScreenRect CGraphics::ClipScreenRectFromVS(const zeus::CVector3f& p1,
const zeus::CVector3f& p2)
2016-02-13 19:42:36 -08:00
{
2016-02-14 20:00:26 -08:00
if (p1.x == 0.f && p1.y == 0.f && p1.z == 0.f)
2016-02-13 19:42:36 -08:00
return {};
2016-02-14 20:00:26 -08:00
if (p2.x == 0.f && p2.y == 0.f && p2.z == 0.f)
2016-02-13 19:42:36 -08:00
return {};
2016-02-14 20:00:26 -08:00
if (p1.y < GetProjectionState().x14_near || p2.y < GetProjectionState().x14_near)
2016-02-13 19:42:36 -08:00
return {};
2016-02-14 20:00:26 -08:00
if (p1.y > GetProjectionState().x18_far || p2.y > GetProjectionState().x18_far)
2016-02-13 19:42:36 -08:00
return {};
2016-03-04 15:04:53 -08:00
zeus::CVector2i sp1 = ProjectPoint(p1);
zeus::CVector2i sp2 = ProjectPoint(p2);
2016-02-14 20:00:26 -08:00
int minX = std::min(sp2.x, sp1.x);
2016-02-13 19:42:36 -08:00
int minX2 = minX & 0xfffffffe;
2016-02-14 20:00:26 -08:00
int minY = std::min(sp2.y, sp1.y);
2016-02-13 19:42:36 -08:00
int minY2 = minY & 0xfffffffe;
if (minX2 >= g_ViewportResolution.x)
return {};
2016-02-14 20:00:26 -08:00
int maxX = abs(sp1.x - sp2.x) + minX;
int maxX2 = (maxX + 2) & 0xfffffffe;
if (maxX2 <= 0 /* ViewportX origin */)
2016-02-13 19:42:36 -08:00
return {};
2016-02-14 20:00:26 -08:00
int finalMinX = std::max(minX, 0 /* ViewportX origin */);
int finalMaxX = std::min(maxX, g_ViewportResolution.x);
2016-02-13 19:42:36 -08:00
if (minY2 >= g_ViewportResolution.y)
return {};
2016-02-14 20:00:26 -08:00
int maxY = abs(sp1.y - sp2.y) + minY;
int maxY2 = (maxY + 2) & 0xfffffffe;
if (maxY2 <= 0 /* ViewportY origin */)
2016-02-13 19:42:36 -08:00
return {};
2016-02-14 20:00:26 -08:00
int finalMinY = std::max(minY, 0 /* ViewportY origin */);
int finalMaxY = std::min(maxY, g_ViewportResolution.y);
2016-02-13 19:42:36 -08:00
2016-02-14 20:00:26 -08:00
int width = maxX2 - minX2;
int height = maxY2 - minY2;
return {true, minX2, minY2, width, height, width,
2016-02-24 18:55:38 -08:00
minX2 / float(g_ViewportResolution.x), maxX2 / float(g_ViewportResolution.x),
2016-02-24 21:09:45 -08:00
1.f - maxY2 / float(g_ViewportResolution.y), 1.f - minY2 / float(g_ViewportResolution.y)};
2016-02-13 19:42:36 -08:00
2016-02-12 16:57:09 -08:00
}
2016-03-04 15:04:53 -08:00
zeus::CVector3f CGraphics::ProjectModelPointToViewportSpace(const zeus::CVector3f& point)
{
2016-03-04 15:04:53 -08:00
zeus::CVector3f pt = g_GXModelView * point;
2016-04-02 22:25:34 -07:00
return GetPerspectiveProjectionMatrix(false).multiplyOneOverW(pt);
}
2016-03-04 15:04:53 -08:00
void CGraphics::SetViewportResolution(const zeus::CVector2i& res)
{
g_ViewportResolution = res;
g_ViewportResolutionHalf = {res.x / 2, res.y / 2};
}
2016-03-30 23:18:56 -07:00
CTimeProvider* CGraphics::g_ExternalTimeProvider = nullptr;
float CGraphics::g_DefaultSeconds;
float CGraphics::GetSecondsMod900()
{
if (!g_ExternalTimeProvider)
return g_DefaultSeconds;
return g_ExternalTimeProvider->x0_currentTime;
}
2016-04-02 22:25:34 -07:00
boo::IGraphicsDataFactory::Platform CGraphics::g_BooPlatform = boo::IGraphicsDataFactory::Platform::Null;
2016-02-14 20:00:26 -08:00
boo::IGraphicsDataFactory* CGraphics::g_BooFactory = nullptr;
boo::IGraphicsCommandQueue* CGraphics::g_BooMainCommandQueue = nullptr;
boo::ITextureR* CGraphics::g_SpareTexture = nullptr;
2016-02-11 18:36:34 -08:00
}