Implement GX lighting API (need to update shader generation)

This commit is contained in:
Phillip Stephens 2022-05-10 01:20:09 -07:00
parent 3cb38cc94c
commit 17136fdfb9
Signed by: Antidote
GPG Key ID: F8BEE4C83DACA60D
5 changed files with 357 additions and 5 deletions

View File

@ -1,7 +1,6 @@
#include "Runtime/Graphics/CGraphics.hpp"
#include "Runtime/CTimeProvider.hpp"
#include "Runtime/Graphics/CLight.hpp"
#include "Runtime/Graphics/CLineRenderer.hpp"
#include "Runtime/Graphics/CTexture.hpp"
#include "Runtime/Graphics/Shaders/CTextSupportShader.hpp"
@ -19,6 +18,8 @@ u32 CGraphics::g_FlippingState;
bool CGraphics::g_LastFrameUsedAbove = false;
bool CGraphics::g_InterruptLastFrameUsedAbove = false;
GX::LightMask CGraphics::g_LightActive{};
std::array<GX::LightObj, GX::MaxLights> CGraphics::g_LightObjs;
std::array<ELightType, GX::MaxLights> CGraphics::g_LightTypes;
zeus::CTransform CGraphics::g_GXModelView;
zeus::CTransform CGraphics::g_GXModelViewInvXpose;
zeus::CTransform CGraphics::g_GXModelMatrix = zeus::CTransform();
@ -80,6 +81,45 @@ void CGraphics::DisableAllLights() {
void CGraphics::LoadLight(ERglLight light, const CLight& info) {
const auto lightId = static_cast<GX::LightID>(1 << light);
#if 0
zeus::CVector3f pos = info.GetPosition();
zeus::CVector3f dir = info.GetDirection();
if (info.GetType() == ELightType::Directional) {
return;
dir = -(g_CameraMatrix.buildMatrix3f() * dir);
GXInitLightPos(&g_LightObjs[static_cast<u32>(light)], dir.x() * 1048576.f, dir.y() * 1048576.f, dir.z() * 1048576.f);
GXInitLightAttn(&g_LightObjs[static_cast<u32>(light)], 1.f, 0.f, 0.f, 1.f, 0.f, 0.f);
} else if (info.GetType() == ELightType::Spot) {
pos = g_CameraMatrix * pos;
GX::LightObj* obj = &g_LightObjs[static_cast<u32>(light)];
GXInitLightPos(obj, pos.x(), pos.y(), pos.z());
dir = g_CameraMatrix.buildMatrix3f() * dir;
GXInitLightDir(obj, dir.x(), dir.y(), dir.z());
GXInitLightAttn(obj, 1.f, 0.f, 0.f, info.GetAttenuationConstant(), info.GetAngleAttenuationLinear(),
info.GetAttenuationQuadratic());
GXInitLightSpot(obj, info.GetSpotCutoff(), GX::SP_COS2);
} else if (info.GetType() == ELightType::Custom) {
pos = g_CameraMatrix * pos;
GX::LightObj* obj = &g_LightObjs[static_cast<u32>(light)];
GXInitLightPos(obj, pos.x(), pos.y(), pos.z());
dir = g_CameraMatrix.buildMatrix3f() * dir;
GXInitLightDir(obj, dir.x(), dir.y(), dir.z());
GXInitLightAttn(obj, info.GetAngleAttenuationConstant(), info.GetAngleAttenuationLinear(),
info.GetAngleAttenuationQuadratic(), info.GetAttenuationConstant(),
info.GetAngleAttenuationLinear(), info.GetAttenuationQuadratic());
} else if (info.GetType() == ELightType::LocalAmbient) {
pos = g_CameraMatrix * pos;
GXInitLightPos(&g_LightObjs[static_cast<u32>(light)], pos.x(), pos.y(), pos.z());
GXInitLightAttn(&g_LightObjs[static_cast<u32>(light)], 1.f, 0.f, 0.f, info.GetAttenuationConstant(),
info.GetAngleAttenuationLinear(), info.GetAttenuationQuadratic());
}
g_LightTypes[static_cast<u32>(light)] = info.GetType();
GX::Color col(info.GetColor().r(), info.GetColor().g(), info.GetColor().b());
GXInitLightColor(&g_LightObjs[static_cast<u32>(light)], col);
GXLoadLightObjImm(&g_LightObjs[static_cast<u32>(light)], lightId);
#else
switch (info.GetType()) {
case ELightType::LocalAmbient:
aurora::gfx::load_light_ambient(lightId, info.GetColor());
@ -103,6 +143,7 @@ void CGraphics::LoadLight(ERglLight light, const CLight& info) {
break;
}
}
#endif
}
void CGraphics::EnableLight(ERglLight light) {
@ -674,7 +715,14 @@ void CGraphics::Startup() {
}
void CGraphics::InitGraphicsVariables() {
// g_lightTypes[0..n] = Directional;
g_LightTypes[0] = ELightType::Directional;
g_LightTypes[1] = ELightType::Directional;
g_LightTypes[2] = ELightType::Directional;
g_LightTypes[3] = ELightType::Directional;
g_LightTypes[4] = ELightType::Directional;
g_LightTypes[5] = ELightType::Directional;
g_LightTypes[6] = ELightType::Directional;
g_LightTypes[7] = ELightType::Directional;
g_LightActive = {};
SetDepthWriteMode(false, g_depthFunc, false);
SetCullMode(ERglCullMode::None);
@ -682,8 +730,8 @@ void CGraphics::InitGraphicsVariables() {
g_IsGXModelMatrixIdentity = false;
// SetIdentityViewPointMatrix();
// SetIdentityModelMatrix();
// SetViewport(...);
// SetPerspective(...);
SetViewport(0, 0, g_Viewport.x8_width, g_Viewport.xc_height);
SetPerspective(60.f, g_Viewport.x8_width / g_Viewport.xc_height, g_Proj.x14_near, g_Proj.x18_far);
SetCopyClear(g_ClearColor, 1.f);
CGX::SetChanMatColor(CGX::EChannelId::Channel0, zeus::skWhite);
// g_RenderState.ResetFlushAll();

View File

@ -1,6 +1,7 @@
#pragma once
#include "Runtime/ConsoleVariables/CVar.hpp"
#include "Runtime/Graphics/CLight.hpp"
#include "Runtime/Graphics/CTevCombiners.hpp"
#include "Runtime/Graphics/GX.hpp"
#include "Runtime/RetroTypes.hpp"
@ -22,7 +23,6 @@ using frame_clock = std::chrono::high_resolution_clock;
namespace metaforce {
class CTexture;
extern CVar* g_disableLighting;
class CLight;
class CTimeProvider;
enum class ERglCullMode : std::underlying_type_t<GX::CullMode> {
@ -214,6 +214,8 @@ public:
static bool g_LastFrameUsedAbove;
static bool g_InterruptLastFrameUsedAbove;
static GX::LightMask g_LightActive;
static std::array<GX::LightObj, GX::MaxLights> g_LightObjs;
static std::array<ELightType, GX::MaxLights> g_LightTypes;
static zeus::CTransform g_GXModelView;
static zeus::CTransform g_GXModelViewInvXpose;
static zeus::CTransform g_GXModelMatrix;

View File

@ -72,6 +72,7 @@ public:
x4c_24_intensityDirty = true;
x4c_25_radiusDirty = true;
}
float GetSpotCutoff() const { return x20_spotCutoff; }
float GetAttenuationConstant() const { return x24_distC; }
float GetAttenuationLinear() const { return x28_distL; }
float GetAttenuationQuadratic() const { return x2c_distQ; }

View File

@ -1,5 +1,9 @@
#pragma once
#ifndef GX_IS_WII
#define GX_IS_WII 0
#endif
#include "../GCNTypes.hpp"
#include <bit>
@ -10,6 +14,12 @@
#include <zeus/CTransform.hpp>
namespace GX {
#if GX_IS_WII
constexpr float LARGE_NUMBER = -1.0e+18f;
#else
constexpr float LARGE_NUMBER = -1048576.0f;
#endif
enum Attr {
VA_PNMTXIDX = 0x0,
VA_TEX0MTXIDX = 0x1,
@ -692,6 +702,39 @@ enum CompType {
RGBA8 = 5,
};
struct LightObj {
u32 __padding[3];
GX::Color color;
float a0 = 1.f;
float a1 = 0.f;
float a2 = 0.f;
float k0 = 1.f;
float k1 = 0.f;
float k2 = 0.f;
float px = 0.f;
float py = 0.f;
float pz = 0.f;
float nx = 0.f;
float ny = 0.f;
float nz = 0.f;
};
enum SpotFn {
SP_OFF,
SP_FLAT,
SP_COS,
SP_COS2,
SP_SHARP,
SP_RING1,
SP_RING2,
};
enum DistAttnFn {
DA_OFF,
DA_GENTLE,
DA_MEDIUM,
DA_STEEP,
};
} // namespace GX
using GXColor = zeus::CColor;
@ -759,3 +802,38 @@ void GXEnd() noexcept;
void GXSetTevSwapModeTable(GX::TevSwapSel id, GX::TevColorChan red, GX::TevColorChan green, GX::TevColorChan blue,
GX::TevColorChan alpha) noexcept;
void GXSetTevSwapMode(GX::TevStageID stage, GX::TevSwapSel rasSel, GX::TevSwapSel texSel) noexcept;
// Lighting
void GXInitLightAttn(GX::LightObj* light, float a0, float a1, float a2, float k0, float k1, float k2);
void GXInitLightAttnA(GX::LightObj* light, float a0, float a1, float a2);
void GXInitLightAttnK(GX::LightObj* light, float k0, float k1, float k2);
void GXInitLightSpot(GX::LightObj* light, float cutoff, GX::SpotFn spotFn);
void GXInitLightDistAttn(GX::LightObj* light, float refDistance, float refBrightness, GX::DistAttnFn distFunc);
constexpr void GXInitLightShininess(GX::LightObj* light, float shininess) {
GXInitLightAttn(light, 0.f, 0.f, 1.f, (shininess) / 2.f, 0.f, 1.f - (shininess) / 2.f);
}
void GXInitLightPos(GX::LightObj* light, float x, float y, float z);
constexpr void GXInitLightPosv(GX::LightObj* light, float vec[3]) { GXInitLightPos(light, vec[0], vec[1], vec[2]); }
void GXInitLightDir(GX::LightObj* light, float nx, float ny, float nz);
constexpr void GXInitLightDirv(GX::LightObj* light, float vec[3]) { GXInitLightDir(light, vec[0], vec[1], vec[2]); }
void GXInitSpecularDir(GX::LightObj* light, float nx, float ny, float nz);
void GXInitSpecularDirHA(GX::LightObj* light, float nx, float ny, float nz, float hx, float hy, float hz);
constexpr void GXInitLightSpecularDirHAv(GX::LightObj* light, float vecn[3], float vech[3]) {
GXInitSpecularDirHA(light, vecn[0], vecn[1], vecn[2], vech[0], vech[1], vech[2]);
}
void GXInitLightColor(GX::LightObj* light, GX::Color col);
void GXLoadLightObjImm(const GX::LightObj* light, GX::LightID id);
void GXLoadLightObjIndx(u32 index, GX::LightID);
void GXGetLightAttnA(const GX::LightObj* light, float* a0, float* a1, float* a2);
void GXGetLightAttnK(const GX::LightObj* light, float* k0, float* k1, float* k2);
void GXGetLightPos(const GX::LightObj* light, float* x, float* y, float* z);
constexpr void GXGetLightPosv(const GX::LightObj* light, float* vec[3]) {
GXGetLightPos(light, vec[0], vec[1], vec[2]);
}
void GXGetLightDir(const GX::LightObj* light, float* nx, float* ny, float* nz);
constexpr void GXGetLightDirv(const GX::LightObj* light, float* vec[3]) {
GXGetLightDir(light, vec[0], vec[1], vec[2]);
}
void GXGetLightColor(const GX::LightObj* light, GX::Color* col);

View File

@ -207,6 +207,229 @@ void GXSetLineWidth(u8 width, GX::TexOffset offs) noexcept {
// TODO
}
// Lighting
void GXInitLightAttn(GX::LightObj* light, float a0, float a1, float a2, float k0, float k1, float k2) {
light->a0 = a0;
light->a1 = a1;
light->a2 = a2;
light->k0 = k0;
light->k1 = k1;
light->k2 = k2;
}
void GXInitLightAttnA(GX::LightObj* light, float a0, float a1, float a2) {
light->a0 = a0;
light->a1 = a1;
light->a2 = a2;
}
void GXInitLightAttnK(GX::LightObj* light, float k0, float k1, float k2) {
light->k0 = k0;
light->k1 = k1;
light->k2 = k2;
}
void GXInitLightSpot(GX::LightObj* light, float cutoff, GX::SpotFn spotFn) {
if (cutoff < 0.f || cutoff > 90.f) {
spotFn = GX::SP_OFF;
}
float cr = (cutoff * M_PIF) / 180.f;
float a0 = 1.f;
float a1 = 0.f;
float a2 = 0.f;
switch (spotFn) {
case GX::SP_OFF:
a0 = 1.f;
a1 = 0.f;
a2 = 0.f;
break;
case GX::SP_FLAT:
a0 = -1000.f * cr;
a1 = 1000.f;
a2 = 0.f;
break;
case GX::SP_COS:
a0 = -cr / (1.f - cr);
a1 = 1.f / (1.f - cr);
a2 = 0.f;
break;
case GX::SP_COS2:
a0 = 0.0f;
a1 = -cr / (1.f - cr);
a2 = 1.f / (1.f - cr);
break;
case GX::SP_SHARP: {
const float d = (1.f - cr) * (1.f - cr);
a0 = cr * (cr - 2.f);
a1 = 2.f / d;
a2 = -1.f / d;
break;
}
case GX::SP_RING1: {
const float d = (1.f - cr) * (1.f - cr);
a0 = 4.f * cr / d;
a1 = 4.f * (1.f + cr) / d;
a2 = -4.f / d;
break;
}
case GX::SP_RING2: {
const float d = (1.f - cr) * (1.f - cr);
a0 = 1.f - 2.f * cr * cr / d;
a1 = 4.f * cr / d;
a2 = -2.f / d;
break;
}
}
light->a0 = a0;
light->a1 = a1;
light->a2 = a2;
}
void GXInitLightDistAttn(GX::LightObj* light, float refDistance, float refBrightness, GX::DistAttnFn distFunc) {
if (refDistance < 0.f || refBrightness < 0.f || refBrightness >= 1.f) {
distFunc = GX::DA_OFF;
}
float k0 = 1.f;
float k1 = 0.f;
float k2 = 0.f;
switch (distFunc) {
case GX::DA_GENTLE:
k0 = 1.0f;
k1 = (1.0f - refBrightness) / (refBrightness * refDistance);
k2 = 0.0f;
break;
case GX::DA_MEDIUM:
k0 = 1.0f;
k1 = 0.5f * (1.0f - refBrightness) / (refBrightness * refDistance);
k2 = 0.5f * (1.0f - refBrightness) / (refBrightness * refDistance * refDistance);
break;
case GX::DA_STEEP:
k0 = 1.0f;
k1 = 0.0f;
k2 = (1.0f - refBrightness) / (refBrightness * refDistance * refDistance);
break;
case GX::DA_OFF:
k0 = 1.0f;
k1 = 0.0f;
k2 = 0.0f;
break;
}
light->k0 = k0;
light->k1 = k1;
light->k2 = k2;
}
void GXInitLightPos(GX::LightObj* light, float x, float y, float z) {
light->px = x;
light->py = y;
light->pz = z;
}
void GXInitLightDir(GX::LightObj* light, float nx, float ny, float nz) {
light->nx = nx;
light->ny = ny;
light->nz = nz;
}
void GXInitSpecularDir(GX::LightObj* light, float nx, float ny, float nz) {
float hx = -nx;
float hy = -ny;
float hz = (-nz + 1.0f);
float mag = ((hx * hx) + (hy * hy) + (hz * hz));
if (mag != 0.0f) {
mag = 1.0f / sqrtf(mag);
}
light->px = (nx * GX::LARGE_NUMBER);
light->py = (ny * GX::LARGE_NUMBER);
light->pz = (nz * GX::LARGE_NUMBER);
light->nx = hx * mag;
light->ny = hy * mag;
light->nz = hz * mag;
}
void GXInitSpecularDirHA(GX::LightObj* light, float nx, float ny, float nz, float hx, float hy, float hz) {
light->px = (nx * GX::LARGE_NUMBER);
light->py = (ny * GX::LARGE_NUMBER);
light->pz = (nz * GX::LARGE_NUMBER);
light->nx = hx;
light->ny = hy;
light->nz = hz;
}
void GXInitLightColor(GX::LightObj* light, GX::Color col) { light->color = col; }
void GXLoadLightObjImm(const GX::LightObj* light, GX::LightID id) {
u32 idx = 0;
switch (id) {
case GX::LIGHT0:
idx = 0;
break;
case GX::LIGHT1:
idx = 1;
break;
case GX::LIGHT2:
idx = 2;
break;
case GX::LIGHT3:
idx = 3;
break;
case GX::LIGHT4:
idx = 4;
break;
case GX::LIGHT5:
idx = 5;
break;
case GX::LIGHT6:
idx = 6;
break;
case GX::LIGHT7:
idx = 7;
break;
default:
idx = 0;
break;
}
aurora::gfx::Light realLight;
realLight.pos.assign(light->px, light->py, light->pz);
realLight.dir.assign(light->nx, light->ny, light->nz);
realLight.angAtt.assign(light->a0, light->a1, light->a2);
realLight.linAtt.assign(light->k0, light->k1, light->k2);
realLight.color.fromRGBA32(light->color.num);
g_gxState.lights[idx] = realLight;
}
/* TODO Figure out a way to implement this, requires GXSetArray */
void GXLoadLightObjIndx(u32 index, GX::LightID) {}
void GXGetLightAttnA(const GX::LightObj* light, float* a0, float* a1, float* a2) {
*a0 = light->a0;
*a1 = light->a1;
*a2 = light->a2;
}
void GXGetLightAttnK(const GX::LightObj* light, float* k0, float* k1, float* k2) {
*k0 = light->k0;
*k1 = light->k1;
*k2 = light->k2;
}
void GXGetLightPos(const GX::LightObj* light, float* x, float* y, float* z) {
*x = light->px;
*z = light->py;
*z = light->pz;
}
void GXGetLightDir(const GX::LightObj* light, float* nx, float* ny, float* nz) {
*nx = light->nx;
*ny = light->ny;
*nz = light->nz;
}
void GXGetLightColor(const GX::LightObj* light, GX::Color* col) { *col = light->color; }
namespace aurora::gfx {
static logvisor::Module Log("aurora::gfx::gx");