mirror of https://github.com/AxioDL/metaforce.git
Implement GX lighting API (need to update shader generation)
This commit is contained in:
parent
3cb38cc94c
commit
17136fdfb9
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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);
|
|
@ -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");
|
||||
|
||||
|
|
Loading…
Reference in New Issue