2022-02-26 16:42:42 +00:00
|
|
|
#include "Runtime/Graphics/CCubeRenderer.hpp"
|
2022-02-25 07:45:25 +00:00
|
|
|
|
2022-02-26 16:42:42 +00:00
|
|
|
#include "Runtime/GameGlobalObjects.hpp"
|
2022-03-12 15:47:20 +00:00
|
|
|
#include "Runtime/Graphics/CCubeMaterial.hpp"
|
|
|
|
#include "Runtime/Graphics/CCubeModel.hpp"
|
|
|
|
#include "Runtime/Graphics/CCubeSurface.hpp"
|
2022-02-26 16:42:42 +00:00
|
|
|
#include "Runtime/Graphics/CDrawable.hpp"
|
|
|
|
#include "Runtime/Graphics/CDrawablePlaneObject.hpp"
|
2022-03-12 15:47:20 +00:00
|
|
|
#include "Runtime/Graphics/CGX.hpp"
|
2022-02-26 16:42:42 +00:00
|
|
|
#include "Runtime/Graphics/CLight.hpp"
|
2022-03-12 15:47:20 +00:00
|
|
|
#include "Runtime/Graphics/CMetroidModelInstance.hpp"
|
2022-02-26 16:42:42 +00:00
|
|
|
#include "Runtime/Graphics/CModel.hpp"
|
2022-03-12 17:03:55 +00:00
|
|
|
#include "Runtime/World/CGameArea.hpp"
|
2022-02-27 20:12:02 +00:00
|
|
|
#include "Runtime/Particle/CParticleGen.hpp"
|
2022-05-13 23:40:19 +00:00
|
|
|
#include "Runtime/Particle/CDecal.hpp"
|
|
|
|
#include "Runtime/Particle/CElementGen.hpp"
|
|
|
|
#include "Runtime/CDvdFile.hpp"
|
2022-02-25 07:45:25 +00:00
|
|
|
|
2022-07-29 20:16:55 +00:00
|
|
|
#include <utility>
|
|
|
|
|
2022-02-25 07:45:25 +00:00
|
|
|
namespace metaforce {
|
|
|
|
static logvisor::Module Log("CCubeRenderer");
|
|
|
|
|
2022-05-14 06:47:29 +00:00
|
|
|
/* TODO: This is to fix some areas exceeding the max drawable count, the proper number is 128 drawables per bucket */
|
|
|
|
// using BucketHolderType = rstl::reserved_vector<CDrawable*, 128>;
|
|
|
|
using BucketHolderType = rstl::reserved_vector<CDrawable*, 132>;
|
2022-02-25 07:45:25 +00:00
|
|
|
static rstl::reserved_vector<CDrawable, 512> sDataHolder;
|
2022-05-14 06:47:29 +00:00
|
|
|
static rstl::reserved_vector<BucketHolderType, 50> sBucketsHolder;
|
2022-02-25 07:45:25 +00:00
|
|
|
static rstl::reserved_vector<CDrawablePlaneObject, 8> sPlaneObjectDataHolder;
|
|
|
|
static rstl::reserved_vector<u16, 8> sPlaneObjectBucketHolder;
|
|
|
|
|
|
|
|
class Buckets {
|
|
|
|
friend class CCubeRenderer;
|
|
|
|
|
|
|
|
static inline rstl::reserved_vector<u16, 50> sBucketIndex;
|
|
|
|
static inline rstl::reserved_vector<CDrawable, 512>* sData = nullptr;
|
2022-05-14 06:47:29 +00:00
|
|
|
static inline rstl::reserved_vector<BucketHolderType, 50>* sBuckets = nullptr;
|
2022-02-25 07:45:25 +00:00
|
|
|
static inline rstl::reserved_vector<CDrawablePlaneObject, 8>* sPlaneObjectData = nullptr;
|
|
|
|
static inline rstl::reserved_vector<u16, 8>* sPlaneObjectBucket = nullptr;
|
|
|
|
static constexpr std::array skWorstMinMaxDistance{99999.0f, -99999.0f};
|
2022-05-14 06:47:29 +00:00
|
|
|
static inline std::array sMinMaxDistance{99999.0f, -99999.0f};
|
2022-02-25 07:45:25 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
static void Clear();
|
|
|
|
static void Sort();
|
|
|
|
static void InsertPlaneObject(float closeDist, float farDist, const zeus::CAABox& aabb, bool invertTest,
|
|
|
|
const zeus::CPlane& plane, bool zOnly, EDrawableType dtype, void* data);
|
|
|
|
static void Insert(const zeus::CVector3f& pos, const zeus::CAABox& aabb, EDrawableType dtype, void* data,
|
|
|
|
const zeus::CPlane& plane, u16 extraSort);
|
|
|
|
static void Shutdown();
|
|
|
|
static void Init();
|
|
|
|
};
|
|
|
|
|
|
|
|
void Buckets::Clear() {
|
|
|
|
sData->clear();
|
|
|
|
sBucketIndex.clear();
|
|
|
|
sPlaneObjectData->clear();
|
|
|
|
sPlaneObjectBucket->clear();
|
2022-05-14 06:47:29 +00:00
|
|
|
for (BucketHolderType& bucket : *sBuckets) {
|
2022-02-25 07:45:25 +00:00
|
|
|
bucket.clear();
|
|
|
|
}
|
|
|
|
sMinMaxDistance = skWorstMinMaxDistance;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Buckets::Sort() {
|
|
|
|
float delta = std::max(1.f, sMinMaxDistance[1] - sMinMaxDistance[0]);
|
|
|
|
float pitch = 49.f / delta;
|
2022-05-14 06:47:29 +00:00
|
|
|
for (auto it = sPlaneObjectData->begin(); it != sPlaneObjectData->end(); ++it) {
|
|
|
|
if (sPlaneObjectBucket->size() != sPlaneObjectBucket->capacity()) {
|
2022-02-25 07:45:25 +00:00
|
|
|
sPlaneObjectBucket->push_back(s16(it - sPlaneObjectData->begin()));
|
2022-05-14 06:47:29 +00:00
|
|
|
}
|
|
|
|
}
|
2022-02-25 07:45:25 +00:00
|
|
|
|
|
|
|
u32 precision = 50;
|
2022-05-14 06:47:29 +00:00
|
|
|
if (!sPlaneObjectBucket->empty()) {
|
2022-02-25 07:45:25 +00:00
|
|
|
std::sort(sPlaneObjectBucket->begin(), sPlaneObjectBucket->end(),
|
|
|
|
[](u16 a, u16 b) { return (*sPlaneObjectData)[a].GetDistance() < (*sPlaneObjectData)[b].GetDistance(); });
|
|
|
|
precision = 50 / u32(sPlaneObjectBucket->size() + 1);
|
|
|
|
pitch = 1.f / (delta / float(precision - 2));
|
|
|
|
|
2022-03-07 03:07:00 +00:00
|
|
|
s32 accum = 0;
|
2022-02-25 07:45:25 +00:00
|
|
|
for (u16 idx : *sPlaneObjectBucket) {
|
|
|
|
++accum;
|
|
|
|
CDrawablePlaneObject& planeObj = (*sPlaneObjectData)[idx];
|
|
|
|
planeObj.x24_targetBucket = u16(precision * accum);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (CDrawable& drawable : *sData) {
|
2022-05-14 06:47:29 +00:00
|
|
|
s32 slot = -1;
|
2022-02-25 07:45:25 +00:00
|
|
|
float relDist = drawable.GetDistance() - sMinMaxDistance[0];
|
|
|
|
if (sPlaneObjectBucket->empty()) {
|
2022-03-07 03:07:00 +00:00
|
|
|
slot = zeus::clamp(1, s32(relDist * pitch), 49);
|
2022-02-25 07:45:25 +00:00
|
|
|
} else {
|
2022-03-07 03:07:00 +00:00
|
|
|
slot = zeus::clamp(0, s32(relDist * pitch), s32(precision) - 2);
|
2022-02-25 07:45:25 +00:00
|
|
|
for (u16 idx : *sPlaneObjectBucket) {
|
|
|
|
CDrawablePlaneObject& planeObj = (*sPlaneObjectData)[idx];
|
2022-05-14 06:47:29 +00:00
|
|
|
bool partial = false;
|
|
|
|
bool full = false;
|
2022-02-25 07:45:25 +00:00
|
|
|
if (planeObj.x3c_25_zOnly) {
|
|
|
|
partial = drawable.GetBounds().max.z() > planeObj.GetPlane().d();
|
|
|
|
full = drawable.GetBounds().min.z() > planeObj.GetPlane().d();
|
|
|
|
} else {
|
|
|
|
partial = planeObj.GetPlane().pointToPlaneDist(
|
|
|
|
drawable.GetBounds().closestPointAlongVector(planeObj.GetPlane().normal())) > 0.f;
|
|
|
|
full = planeObj.GetPlane().pointToPlaneDist(
|
|
|
|
drawable.GetBounds().furthestPointAlongVector(planeObj.GetPlane().normal())) > 0.f;
|
|
|
|
}
|
2022-05-14 06:47:29 +00:00
|
|
|
bool cont = false;
|
|
|
|
if (drawable.GetType() == EDrawableType::Particle) {
|
2022-02-25 07:45:25 +00:00
|
|
|
cont = planeObj.x3c_24_invertTest ? !partial : full;
|
2022-05-14 06:47:29 +00:00
|
|
|
} else {
|
2022-02-25 07:45:25 +00:00
|
|
|
cont = planeObj.x3c_24_invertTest ? (!partial || !full) : (partial || full);
|
2022-05-14 06:47:29 +00:00
|
|
|
}
|
|
|
|
if (!cont) {
|
2022-02-25 07:45:25 +00:00
|
|
|
break;
|
2022-05-14 06:47:29 +00:00
|
|
|
}
|
|
|
|
slot += s32(precision);
|
2022-02-25 07:45:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-14 06:47:29 +00:00
|
|
|
if (slot == -1) {
|
2022-02-25 07:45:25 +00:00
|
|
|
slot = 49;
|
2022-05-14 06:47:29 +00:00
|
|
|
}
|
|
|
|
BucketHolderType& bucket = (*sBuckets)[slot];
|
|
|
|
if (bucket.size() < bucket.capacity()) {
|
2022-02-25 07:45:25 +00:00
|
|
|
bucket.push_back(&drawable);
|
2022-05-14 06:47:29 +00:00
|
|
|
}
|
2022-02-25 07:45:25 +00:00
|
|
|
// else
|
|
|
|
// Log.report(logvisor::Fatal, FMT_STRING("Full bucket!!!"));
|
|
|
|
}
|
|
|
|
|
|
|
|
u16 bucketIdx = u16(sBuckets->size());
|
|
|
|
for (auto it = sBuckets->rbegin(); it != sBuckets->rend(); ++it) {
|
|
|
|
--bucketIdx;
|
|
|
|
sBucketIndex.push_back(bucketIdx);
|
2022-05-14 06:47:29 +00:00
|
|
|
BucketHolderType& bucket = *it;
|
2022-02-25 07:45:25 +00:00
|
|
|
if (bucket.size()) {
|
|
|
|
std::sort(bucket.begin(), bucket.end(), [](CDrawable* a, CDrawable* b) {
|
|
|
|
if (a->GetDistance() == b->GetDistance())
|
|
|
|
return a->GetExtraSort() > b->GetExtraSort();
|
|
|
|
return a->GetDistance() > b->GetDistance();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto it = sPlaneObjectBucket->rbegin(); it != sPlaneObjectBucket->rend(); ++it) {
|
|
|
|
CDrawablePlaneObject& planeObj = (*sPlaneObjectData)[*it];
|
2022-05-14 06:47:29 +00:00
|
|
|
BucketHolderType& bucket = (*sBuckets)[planeObj.x24_targetBucket];
|
2022-02-25 07:45:25 +00:00
|
|
|
bucket.push_back(&planeObj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Buckets::InsertPlaneObject(float closeDist, float farDist, const zeus::CAABox& aabb, bool invertTest,
|
|
|
|
const zeus::CPlane& plane, bool zOnly, EDrawableType dtype, void* data) {
|
|
|
|
if (sPlaneObjectData->size() == sPlaneObjectData->capacity()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sPlaneObjectData->emplace_back(dtype, closeDist, farDist, aabb, invertTest, plane, zOnly, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Buckets::Insert(const zeus::CVector3f& pos, const zeus::CAABox& aabb, EDrawableType dtype, void* data,
|
|
|
|
const zeus::CPlane& plane, u16 extraSort) {
|
|
|
|
if (sData->size() == sData->capacity()) {
|
|
|
|
Log.report(logvisor::Fatal, FMT_STRING("Rendering buckets filled to capacity"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const float dist = plane.pointToPlaneDist(pos);
|
|
|
|
sData->emplace_back(dtype, extraSort, dist, aabb, data);
|
|
|
|
sMinMaxDistance[0] = std::min(sMinMaxDistance[0], dist);
|
|
|
|
sMinMaxDistance[1] = std::max(sMinMaxDistance[1], dist);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Buckets::Shutdown() {
|
|
|
|
sData = nullptr;
|
|
|
|
sBuckets = nullptr;
|
|
|
|
sPlaneObjectData = nullptr;
|
|
|
|
sPlaneObjectBucket = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Buckets::Init() {
|
|
|
|
sData = &sDataHolder;
|
|
|
|
sBuckets = &sBucketsHolder;
|
|
|
|
sBuckets->resize(50);
|
|
|
|
sPlaneObjectData = &sPlaneObjectDataHolder;
|
|
|
|
sPlaneObjectBucket = &sPlaneObjectBucketHolder;
|
|
|
|
sMinMaxDistance = skWorstMinMaxDistance;
|
|
|
|
}
|
|
|
|
|
2022-02-27 20:12:02 +00:00
|
|
|
CCubeRenderer::CAreaListItem::CAreaListItem(const std::vector<CMetroidModelInstance>* geom,
|
|
|
|
const CAreaRenderOctTree* octTree,
|
2022-03-06 04:50:54 +00:00
|
|
|
std::unique_ptr<std::vector<TCachedToken<CTexture>>>&& textures,
|
|
|
|
std::unique_ptr<std::vector<std::unique_ptr<CCubeModel>>>&& models,
|
2022-03-07 03:07:00 +00:00
|
|
|
s32 areaIdx)
|
2022-02-27 20:12:02 +00:00
|
|
|
: x0_geometry(geom)
|
|
|
|
, x4_octTree(octTree)
|
|
|
|
, x8_textures(std::move(textures))
|
|
|
|
, x10_models(std::move(models))
|
|
|
|
, x18_areaIdx(areaIdx) {}
|
|
|
|
|
2022-02-25 07:45:25 +00:00
|
|
|
CCubeRenderer::CCubeRenderer(IObjectStore& store, IFactory& resFac) : x8_factory(resFac), xc_store(store) {
|
2022-03-06 04:50:54 +00:00
|
|
|
void* data = xe4_blackTex.Lock();
|
|
|
|
memset(data, 0, 32);
|
|
|
|
xe4_blackTex.UnLock();
|
2022-02-25 07:45:25 +00:00
|
|
|
GenerateReflectionTex();
|
|
|
|
GenerateFogVolumeRampTex();
|
|
|
|
GenerateSphereRampTex();
|
|
|
|
LoadThermoPalette();
|
|
|
|
g_Renderer = this;
|
|
|
|
Buckets::Init();
|
|
|
|
// GX draw sync
|
|
|
|
}
|
2022-02-26 16:42:42 +00:00
|
|
|
|
2022-02-27 20:12:02 +00:00
|
|
|
CCubeRenderer::~CCubeRenderer() { g_Renderer = nullptr; }
|
2022-02-26 16:42:42 +00:00
|
|
|
|
2022-03-12 15:47:20 +00:00
|
|
|
void CCubeRenderer::GenerateReflectionTex() {
|
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCubeRenderer::GenerateFogVolumeRampTex() {
|
2022-07-02 00:47:45 +00:00
|
|
|
constexpr double fogVolFar = 750.0;
|
|
|
|
constexpr double fogVolNear = 0.2;
|
|
|
|
u8* data = x1b8_fogVolumeRamp.Lock();
|
|
|
|
u16 height = x1b8_fogVolumeRamp.GetHeight();
|
|
|
|
u16 width = x1b8_fogVolumeRamp.GetWidth();
|
|
|
|
for (size_t y = 0; y < height; ++y) {
|
|
|
|
for (size_t x = 0; x < width; ++x) {
|
|
|
|
const int tmp = int(y << 16 | x << 8 | 0x7f);
|
|
|
|
const double a =
|
|
|
|
zeus::clamp(0.0,
|
|
|
|
(-150.0 / (tmp / double(0xffffff) * (fogVolFar - fogVolNear) - fogVolFar) - fogVolNear) * 3.0 /
|
|
|
|
(fogVolFar - fogVolNear),
|
|
|
|
1.0);
|
|
|
|
data[y * width + x] = (a * a + a) / 2.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
x1b8_fogVolumeRamp.UnLock();
|
2022-03-12 15:47:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCubeRenderer::GenerateSphereRampTex() {
|
2022-05-13 23:40:19 +00:00
|
|
|
u8* data = x220_sphereRamp.Lock();
|
2022-07-01 04:00:29 +00:00
|
|
|
const size_t height = x220_sphereRamp.GetHeight();
|
|
|
|
const size_t width = x220_sphereRamp.GetWidth();
|
|
|
|
const float halfRes = height / 2.f;
|
|
|
|
for (size_t y = 0; y < height; ++y) {
|
|
|
|
for (size_t x = 0; x < width; ++x) {
|
2022-05-13 23:40:19 +00:00
|
|
|
const zeus::CVector2f vec{
|
2022-07-01 04:00:29 +00:00
|
|
|
(static_cast<float>(x) - halfRes) / halfRes,
|
|
|
|
(static_cast<float>(y) - halfRes) / halfRes,
|
2022-05-13 23:40:19 +00:00
|
|
|
};
|
2022-07-02 00:47:45 +00:00
|
|
|
data[y * width + x] = 255 - zeus::clamp(0.f, vec.canBeNormalized() ? vec.magnitude() : 0.f, 1.f) * 255;
|
2022-05-13 23:40:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
x220_sphereRamp.UnLock();
|
2022-03-12 15:47:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCubeRenderer::LoadThermoPalette() {
|
2022-05-19 07:57:30 +00:00
|
|
|
auto* out = x288_thermoPalette.Lock();
|
2022-05-13 23:40:19 +00:00
|
|
|
TToken<CTexture> token = xc_store.GetObj("TXTR_ThermoPalette");
|
2022-05-19 07:57:30 +00:00
|
|
|
const auto* data = token.GetObj()->GetPalette()->GetPaletteData();
|
|
|
|
memcpy(out, data, 32);
|
2022-05-13 23:40:19 +00:00
|
|
|
x288_thermoPalette.UnLock();
|
2022-03-12 15:47:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCubeRenderer::ReallyDrawPhazonSuitIndirectEffect(const zeus::CColor& vertColor, CTexture& maskTex,
|
|
|
|
CTexture& indTex, const zeus::CColor& modColor, float scale,
|
|
|
|
float offX, float offY) {
|
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCubeRenderer::ReallyDrawPhazonSuitEffect(const zeus::CColor& modColor, CTexture& maskTex) {
|
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
|
2022-07-02 00:47:45 +00:00
|
|
|
void CCubeRenderer::DoPhazonSuitIndirectAlphaBlur(float blurRadius, float f2) {
|
2022-03-12 15:47:20 +00:00
|
|
|
// TODO
|
|
|
|
}
|
2022-03-06 04:50:54 +00:00
|
|
|
|
|
|
|
void CCubeRenderer::AddWorldSurfaces(CCubeModel& model) {
|
|
|
|
for (auto* it = model.GetFirstSortedSurface(); it != nullptr; it = it->GetNextSurface()) {
|
|
|
|
auto mat = model.GetMaterialByIndex(it->GetMaterialIndex());
|
|
|
|
auto blend = mat.GetCompressedBlend();
|
|
|
|
auto bounds = it->GetBounds();
|
|
|
|
auto pos = bounds.closestPointAlongVector(xb0_viewPlane.normal());
|
|
|
|
Buckets::Insert(pos, bounds, EDrawableType::WorldSurface, it, xb0_viewPlane, static_cast<u16>(blend == 0x50004));
|
|
|
|
}
|
|
|
|
}
|
2022-03-12 15:47:20 +00:00
|
|
|
|
2022-02-26 16:42:42 +00:00
|
|
|
void CCubeRenderer::AddStaticGeometry(const std::vector<CMetroidModelInstance>* geometry,
|
2022-03-07 03:07:00 +00:00
|
|
|
const CAreaRenderOctTree* octTree, s32 areaIdx) {
|
2022-03-06 04:50:54 +00:00
|
|
|
auto search = FindStaticGeometry(geometry);
|
|
|
|
if (search == x1c_areaListItems.end()) {
|
|
|
|
auto textures = std::make_unique<std::vector<TCachedToken<CTexture>>>();
|
|
|
|
auto models = std::make_unique<std::vector<std::unique_ptr<CCubeModel>>>();
|
|
|
|
if (!geometry->empty()) {
|
|
|
|
CCubeModel::MakeTexturesFromMats((*geometry)[0].GetMaterialPointer(), *textures.get(), &xc_store, false);
|
|
|
|
models->reserve(geometry->size());
|
2022-03-07 03:07:00 +00:00
|
|
|
s32 instIdx = 0;
|
2022-03-06 04:50:54 +00:00
|
|
|
for (const CMetroidModelInstance& inst : *geometry) {
|
|
|
|
models->emplace_back(
|
|
|
|
std::make_unique<CCubeModel>(const_cast<std::vector<CCubeSurface>*>(inst.GetSurfaces()), textures.get(),
|
|
|
|
const_cast<u8*>(inst.GetMaterialPointer()),
|
|
|
|
const_cast<std::vector<zeus::CVector3f>*>(inst.GetVertexPointer()),
|
|
|
|
const_cast<std::vector<zeus::CColor>*>(inst.GetColorPointer()),
|
|
|
|
const_cast<std::vector<zeus::CVector3f>*>(inst.GetNormalPointer()),
|
2022-03-08 07:44:46 +00:00
|
|
|
const_cast<std::vector<aurora::Vec2<float>>*>(inst.GetTCPointer()),
|
|
|
|
const_cast<std::vector<aurora::Vec2<float>>*>(inst.GetPackedTCPointer()),
|
2022-03-06 04:50:54 +00:00
|
|
|
inst.GetBoundingBox(), inst.GetFlags(), false, instIdx));
|
|
|
|
++instIdx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
x1c_areaListItems.emplace_back(geometry, octTree, std::move(textures), std::move(models), areaIdx);
|
|
|
|
}
|
|
|
|
}
|
2022-02-27 21:58:27 +00:00
|
|
|
|
2022-02-27 20:12:02 +00:00
|
|
|
void CCubeRenderer::EnablePVS(const CPVSVisSet& set, u32 areaIdx) {
|
|
|
|
if (!xdc_) {
|
|
|
|
xc8_pvs.emplace(set);
|
|
|
|
xdc_ = true;
|
|
|
|
} else {
|
|
|
|
xc8_pvs.emplace(set);
|
|
|
|
}
|
|
|
|
|
|
|
|
xe0_pvsAreaIdx = areaIdx;
|
|
|
|
}
|
2022-02-27 21:58:27 +00:00
|
|
|
|
2022-02-27 20:12:02 +00:00
|
|
|
void CCubeRenderer::DisablePVS() { xc8_pvs.reset(); }
|
2022-02-27 21:58:27 +00:00
|
|
|
|
2022-03-07 03:07:00 +00:00
|
|
|
void CCubeRenderer::RemoveStaticGeometry(const std::vector<CMetroidModelInstance>* geometry) {
|
|
|
|
auto search = FindStaticGeometry(geometry);
|
|
|
|
if (search != x1c_areaListItems.end()) {
|
|
|
|
x1c_areaListItems.erase(search);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-12 05:57:24 +00:00
|
|
|
void CCubeRenderer::DrawUnsortedGeometry(s32 areaIdx, s32 mask, s32 targetMask) {
|
2022-03-27 00:23:16 +00:00
|
|
|
SCOPED_GRAPHICS_DEBUG_GROUP(
|
2022-05-12 05:57:24 +00:00
|
|
|
fmt::format(FMT_STRING("CCubeRenderer::DrawUnsortedGeometry areaIdx={} mask={} targetMask={}"), areaIdx, mask,
|
|
|
|
targetMask)
|
|
|
|
.c_str(),
|
2022-03-27 00:23:16 +00:00
|
|
|
zeus::skBlue);
|
|
|
|
|
2022-03-06 21:01:25 +00:00
|
|
|
SetupRendererStates(true);
|
|
|
|
CModelFlags flags;
|
|
|
|
CAreaListItem* lastOctreeItem = nullptr;
|
|
|
|
|
|
|
|
for (CAreaListItem& item : x1c_areaListItems) {
|
2022-03-07 03:07:00 +00:00
|
|
|
if (areaIdx != -1 && item.x18_areaIdx != areaIdx) {
|
2022-03-06 21:01:25 +00:00
|
|
|
continue;
|
2022-03-07 03:07:00 +00:00
|
|
|
}
|
2022-03-06 21:01:25 +00:00
|
|
|
|
2022-03-07 03:07:00 +00:00
|
|
|
if (item.x4_octTree != nullptr) {
|
2022-03-06 21:01:25 +00:00
|
|
|
lastOctreeItem = &item;
|
2022-03-07 03:07:00 +00:00
|
|
|
}
|
2022-03-06 21:01:25 +00:00
|
|
|
|
|
|
|
CPVSVisSet* pvs = nullptr;
|
2022-03-07 03:07:00 +00:00
|
|
|
if (xc8_pvs) {
|
2022-03-06 21:01:25 +00:00
|
|
|
pvs = &*xc8_pvs;
|
2022-03-07 03:07:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (xe0_pvsAreaIdx != item.x18_areaIdx) {
|
2022-03-06 21:01:25 +00:00
|
|
|
pvs = nullptr;
|
2022-03-07 03:07:00 +00:00
|
|
|
}
|
2022-03-06 21:01:25 +00:00
|
|
|
|
|
|
|
u32 idx = 0;
|
|
|
|
for (auto it = item.x10_models->begin(); it != item.x10_models->end(); ++it, ++idx) {
|
|
|
|
const auto& model = *it;
|
2022-03-07 03:07:00 +00:00
|
|
|
if (pvs != nullptr) {
|
2022-03-06 21:01:25 +00:00
|
|
|
bool vis = pvs->GetVisible(idx) != EPVSVisSetState::EndOfTree;
|
|
|
|
switch (xc0_pvsMode) {
|
|
|
|
case EPVSMode::PVS: {
|
|
|
|
if (!vis) {
|
|
|
|
model->SetVisible(false);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case EPVSMode::PVSAndMask: {
|
|
|
|
if (!vis && (model->GetFlags() & mask) != targetMask) {
|
|
|
|
model->SetVisible(false);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((model->GetFlags() & mask) != targetMask) {
|
|
|
|
model->SetVisible(false);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!x44_frustumPlanes.aabbFrustumTest(model->GetBounds())) {
|
|
|
|
model->SetVisible(false);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x318_25_drawWireframe) {
|
|
|
|
model->SetVisible(false);
|
|
|
|
HandleUnsortedModelWireframe(lastOctreeItem, *model);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
model->SetVisible(true);
|
|
|
|
HandleUnsortedModel(lastOctreeItem, *model, flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SetupCGraphicsState();
|
|
|
|
}
|
|
|
|
|
2022-03-07 03:07:00 +00:00
|
|
|
void CCubeRenderer::DrawSortedGeometry(s32 areaIdx, s32 mask, s32 targetMask) {
|
2022-03-27 00:23:16 +00:00
|
|
|
SCOPED_GRAPHICS_DEBUG_GROUP(
|
|
|
|
fmt::format(FMT_STRING("CCubeRenderer::DrawSortedGeometry areaIdx={} mask={} targetMask={}"), areaIdx, mask,
|
2022-05-14 06:47:29 +00:00
|
|
|
targetMask)
|
|
|
|
.c_str(),
|
2022-03-27 00:23:16 +00:00
|
|
|
zeus::skBlue);
|
|
|
|
|
2022-03-06 04:50:54 +00:00
|
|
|
SetupRendererStates(true);
|
|
|
|
const CAreaListItem* item = nullptr;
|
|
|
|
for (const auto& areaListItem : x1c_areaListItems) {
|
|
|
|
if (areaIdx == -1 || areaIdx == areaListItem.x18_areaIdx) {
|
|
|
|
if (areaListItem.x4_octTree != nullptr) {
|
|
|
|
item = &areaListItem;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto& model : *areaListItem.x10_models) {
|
|
|
|
if (model->IsVisible()) {
|
|
|
|
AddWorldSurfaces(*model);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-03-03 08:33:24 +00:00
|
|
|
Buckets::Sort();
|
2022-03-06 04:50:54 +00:00
|
|
|
RenderBucketItems(item);
|
|
|
|
SetupCGraphicsState();
|
|
|
|
DrawRenderBucketsDebug();
|
2022-03-03 08:33:24 +00:00
|
|
|
Buckets::Clear();
|
|
|
|
}
|
2022-03-06 04:50:54 +00:00
|
|
|
|
2022-03-07 03:07:00 +00:00
|
|
|
void CCubeRenderer::DrawStaticGeometry(s32 areaIdx, s32 mask, s32 targetMask) {
|
|
|
|
DrawUnsortedGeometry(areaIdx, mask, targetMask);
|
|
|
|
DrawSortedGeometry(areaIdx, mask, targetMask);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCubeRenderer::DrawAreaGeometry(s32 areaIdx, s32 mask, s32 targetMask) {
|
2022-03-27 00:23:16 +00:00
|
|
|
SCOPED_GRAPHICS_DEBUG_GROUP(
|
|
|
|
fmt::format(FMT_STRING("CCubeRenderer::DrawAreaGeometry areaIdx={} mask={} targetMask={}"), areaIdx, mask,
|
2022-05-14 06:47:29 +00:00
|
|
|
targetMask)
|
|
|
|
.c_str(),
|
2022-03-27 00:23:16 +00:00
|
|
|
zeus::skBlue);
|
|
|
|
|
2022-03-07 03:07:00 +00:00
|
|
|
x318_30_inAreaDraw = true;
|
|
|
|
SetupRendererStates(true);
|
2022-03-08 22:21:15 +00:00
|
|
|
constexpr CModelFlags flags{0, 0, 3, zeus::skWhite};
|
2022-03-07 03:07:00 +00:00
|
|
|
|
|
|
|
for (CAreaListItem& item : x1c_areaListItems) {
|
2022-07-01 04:20:43 +00:00
|
|
|
if (areaIdx == -1 || item.x18_areaIdx == areaIdx) {
|
2022-03-07 03:07:00 +00:00
|
|
|
CPVSVisSet* pvs = xc8_pvs ? &*xc8_pvs : nullptr;
|
|
|
|
if (xe0_pvsAreaIdx != item.x18_areaIdx) {
|
|
|
|
pvs = nullptr;
|
|
|
|
}
|
|
|
|
s32 modelIdx = 0;
|
|
|
|
for (auto it = item.x10_models->begin(); it != item.x10_models->end(); ++it, ++modelIdx) {
|
|
|
|
const auto& model = *it;
|
|
|
|
if (pvs != nullptr) {
|
|
|
|
bool visible = pvs->GetVisible(modelIdx) != EPVSVisSetState::EndOfTree;
|
|
|
|
if ((xc0_pvsMode == EPVSMode::PVS && !visible) || (xc0_pvsMode == EPVSMode::PVSAndMask && visible)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((model->GetFlags() & mask) != targetMask) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!x44_frustumPlanes.aabbFrustumTest(model->GetBounds())) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-06-30 00:56:30 +00:00
|
|
|
model->SetArraysCurrent();
|
2022-03-07 03:07:00 +00:00
|
|
|
for (const auto* surf = model->GetFirstUnsortedSurface(); surf != nullptr; surf = surf->GetNextSurface()) {
|
2022-03-08 22:21:15 +00:00
|
|
|
model->DrawSurface(*surf, flags);
|
2022-03-07 03:07:00 +00:00
|
|
|
}
|
|
|
|
for (const auto* surf = model->GetFirstSortedSurface(); surf != nullptr; surf = surf->GetNextSurface()) {
|
2022-03-08 22:21:15 +00:00
|
|
|
model->DrawSurface(*surf, flags);
|
2022-03-07 03:07:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-03-06 04:50:54 +00:00
|
|
|
|
2022-06-30 00:56:30 +00:00
|
|
|
SetupCGraphicsState();
|
2022-03-07 03:07:00 +00:00
|
|
|
x318_30_inAreaDraw = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCubeRenderer::RenderBucketItems(const CAreaListItem* item) {
|
2022-05-13 23:40:19 +00:00
|
|
|
SCOPED_GRAPHICS_DEBUG_GROUP(
|
|
|
|
fmt::format(FMT_STRING("CCubeRenderer::RenderBucketItems areaIdx={}"), item->x18_areaIdx).c_str(), zeus::skBlue);
|
2022-03-27 00:23:16 +00:00
|
|
|
|
2022-03-07 03:07:00 +00:00
|
|
|
CCubeModel* lastModel = nullptr;
|
|
|
|
EDrawableType lastDrawableType = EDrawableType::Invalid;
|
|
|
|
for (u16 idx : Buckets::sBucketIndex) {
|
2022-05-14 06:47:29 +00:00
|
|
|
BucketHolderType& bucket = (*Buckets::sBuckets)[idx];
|
2022-03-07 03:07:00 +00:00
|
|
|
for (CDrawable* drawable : bucket) {
|
|
|
|
EDrawableType type = drawable->GetType();
|
|
|
|
switch (type) {
|
|
|
|
case EDrawableType::Particle: {
|
|
|
|
if (lastDrawableType != EDrawableType::Particle) {
|
|
|
|
SetupCGraphicsState();
|
|
|
|
}
|
|
|
|
|
|
|
|
static_cast<CParticleGen*>(drawable->GetData())->Render();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case EDrawableType::WorldSurface: {
|
|
|
|
if (lastDrawableType != EDrawableType::WorldSurface) {
|
|
|
|
SetupRendererStates(false);
|
|
|
|
lastModel = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto* surface = static_cast<CCubeSurface*>(drawable->GetData());
|
|
|
|
auto* model = surface->GetParent();
|
|
|
|
if (model != lastModel) {
|
|
|
|
model->SetArraysCurrent();
|
|
|
|
ActivateLightsForModel(item, *model);
|
|
|
|
}
|
|
|
|
model->DrawSurface(*surface, CModelFlags(0, 0, 1, zeus::skWhite));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
if (type != lastDrawableType) {
|
|
|
|
CCubeMaterial::EnsureTevsDirect();
|
|
|
|
}
|
|
|
|
if (xa8_drawableCallback != nullptr) {
|
|
|
|
xa8_drawableCallback(drawable->GetData(), xac_drawableCallbackUserData, s32(drawable->GetType()) - 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lastDrawableType = type;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-03-12 15:47:20 +00:00
|
|
|
|
|
|
|
void CCubeRenderer::PostRenderFogs() {
|
2022-07-02 00:47:45 +00:00
|
|
|
for (const auto& warp : x2c4_spaceWarps) {
|
|
|
|
ReallyDrawSpaceWarp(warp.first, warp.second);
|
|
|
|
}
|
|
|
|
x2c4_spaceWarps.clear();
|
|
|
|
|
|
|
|
x2ac_fogVolumes.sort([](const CFogVolumeListItem& a, const CFogVolumeListItem& b) {
|
|
|
|
zeus::CAABox aabbA = a.x34_aabb.getTransformedAABox(a.x0_transform);
|
|
|
|
bool insideA =
|
|
|
|
aabbA.pointInside(zeus::CVector3f(CGraphics::g_ViewPoint.x(), CGraphics::g_ViewPoint.y(), aabbA.min.z()));
|
|
|
|
|
|
|
|
zeus::CAABox aabbB = b.x34_aabb.getTransformedAABox(b.x0_transform);
|
|
|
|
bool insideB =
|
|
|
|
aabbB.pointInside(zeus::CVector3f(CGraphics::g_ViewPoint.x(), CGraphics::g_ViewPoint.y(), aabbB.min.z()));
|
|
|
|
|
|
|
|
if (insideA != insideB) {
|
|
|
|
return insideA;
|
|
|
|
}
|
|
|
|
|
|
|
|
float dotA = aabbA.furthestPointAlongVector(CGraphics::g_ViewMatrix.basis[1]).dot(CGraphics::g_ViewMatrix.basis[1]);
|
|
|
|
float dotB = aabbB.furthestPointAlongVector(CGraphics::g_ViewMatrix.basis[1]).dot(CGraphics::g_ViewMatrix.basis[1]);
|
|
|
|
return dotA < dotB;
|
|
|
|
});
|
|
|
|
for (const CFogVolumeListItem& fog : x2ac_fogVolumes) {
|
|
|
|
CGraphics::SetModelMatrix(fog.x0_transform);
|
|
|
|
ReallyRenderFogVolume(fog.x30_color, fog.x34_aabb, fog.x4c_model.GetObj(), fog.x5c_skinnedModel);
|
|
|
|
}
|
|
|
|
x2ac_fogVolumes.clear();
|
2022-03-12 15:47:20 +00:00
|
|
|
}
|
|
|
|
|
2022-02-27 21:17:44 +00:00
|
|
|
void CCubeRenderer::SetModelMatrix(const zeus::CTransform& xf) { CGraphics::SetModelMatrix(xf); }
|
|
|
|
|
2022-03-06 21:01:25 +00:00
|
|
|
void CCubeRenderer::HandleUnsortedModel(CAreaListItem* areaItem, CCubeModel& model, const CModelFlags& flags) {
|
|
|
|
if (model.GetFirstUnsortedSurface() == nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
model.SetArraysCurrent();
|
|
|
|
ActivateLightsForModel(areaItem, model);
|
2022-03-07 03:07:00 +00:00
|
|
|
for (auto* it = model.GetFirstUnsortedSurface(); it != nullptr; it = it->GetNextSurface()) {
|
2022-03-06 21:01:25 +00:00
|
|
|
model.DrawSurface(*it, CModelFlags(0, 0, 3, zeus::skWhite));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCubeRenderer::HandleUnsortedModelWireframe(CAreaListItem* areaItem, CCubeModel& model) {
|
|
|
|
model.SetArraysCurrent();
|
|
|
|
ActivateLightsForModel(areaItem, model);
|
|
|
|
for (auto* it = model.GetFirstUnsortedSurface(); it != nullptr; it = it->GetNextSurface()) {
|
|
|
|
model.DrawSurfaceWireframe(*it);
|
|
|
|
}
|
|
|
|
for (auto* it = model.GetFirstSortedSurface(); it != nullptr; it = it->GetNextSurface()) {
|
|
|
|
model.DrawSurfaceWireframe(*it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-12 17:03:55 +00:00
|
|
|
constexpr bool TestBit(const u32* words, size_t bit) { return (words[bit / 32] & (1U << (bit & 0x1f))) != 0; }
|
2022-03-13 19:14:11 +00:00
|
|
|
|
|
|
|
void CCubeRenderer::ActivateLightsForModel(const CAreaListItem* areaItem, CCubeModel& model) {
|
|
|
|
constexpr u32 LightCount = 4;
|
|
|
|
GX::LightMask lightMask;
|
|
|
|
|
|
|
|
if (!x300_dynamicLights.empty()) {
|
|
|
|
std::array<u32, LightCount> addedLights{};
|
|
|
|
std::array<float, LightCount> lightRads{-1.f, -1.f, -1.f, -1.f};
|
|
|
|
|
|
|
|
u32 lightOctreeWordCount = 0;
|
|
|
|
const u32* lightOctreeWords = nullptr;
|
|
|
|
if (areaItem != nullptr && model.GetIndex() != UINT32_MAX) {
|
|
|
|
lightOctreeWordCount = areaItem->x4_octTree->x14_bitmapWordCount;
|
|
|
|
lightOctreeWords = areaItem->x1c_lightOctreeWords.data();
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 lightIdx = 0;
|
|
|
|
for (const auto& light : x300_dynamicLights) {
|
2022-03-20 00:52:13 +00:00
|
|
|
if (lightIdx >= LightCount) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-03-13 19:14:11 +00:00
|
|
|
if (lightOctreeWords == nullptr || TestBit(lightOctreeWords, model.GetIndex())) {
|
|
|
|
bool loaded = false;
|
|
|
|
const float radius =
|
|
|
|
model.GetBounds().intersectionRadius(zeus::CSphere(light.GetPosition(), light.GetRadius()));
|
|
|
|
|
|
|
|
if (lightIdx > 0) {
|
|
|
|
for (u32 i = 0; i < lightIdx; ++i) {
|
|
|
|
if (addedLights[i] == light.GetId()) {
|
|
|
|
if (radius >= 0.f && radius < lightRads[i]) {
|
|
|
|
lightRads[i] = radius;
|
|
|
|
CGraphics::LoadLight(i, light);
|
|
|
|
loaded = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!loaded) {
|
|
|
|
lightRads[lightIdx] = radius;
|
|
|
|
if (radius >= 0.f) {
|
|
|
|
CGraphics::LoadLight(lightIdx, light);
|
|
|
|
addedLights[lightIdx] = light.GetId();
|
|
|
|
lightMask.set(lightIdx);
|
|
|
|
++lightIdx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lightOctreeWords += lightOctreeWordCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lightMask.any()) {
|
|
|
|
CGraphics::SetLightState(lightMask);
|
|
|
|
CGX::SetChanMatColor(CGX::EChannelId::Channel0, zeus::skWhite);
|
|
|
|
} else {
|
|
|
|
CGraphics::DisableAllLights();
|
2022-03-13 19:17:13 +00:00
|
|
|
CGX::SetChanMatColor(CGX::EChannelId::Channel0, CGX::GetChanAmbColor(CGX::EChannelId::Channel0));
|
2022-03-13 19:14:11 +00:00
|
|
|
}
|
|
|
|
}
|
2022-03-12 15:47:20 +00:00
|
|
|
|
2022-02-27 20:12:02 +00:00
|
|
|
void CCubeRenderer::AddParticleGen(CParticleGen& gen) {
|
|
|
|
auto bounds = gen.GetBounds();
|
|
|
|
|
|
|
|
if (bounds) {
|
|
|
|
auto closestPoint = bounds->closestPointAlongVector(xb0_viewPlane.normal());
|
|
|
|
Buckets::Insert(closestPoint, *bounds, EDrawableType::Particle, reinterpret_cast<void*>(&gen), xb0_viewPlane, 0);
|
|
|
|
}
|
|
|
|
}
|
2022-02-27 21:58:27 +00:00
|
|
|
|
2022-02-27 20:12:02 +00:00
|
|
|
void CCubeRenderer::AddParticleGen(CParticleGen& gen, const zeus::CVector3f& pos, const zeus::CAABox& bounds) {
|
|
|
|
Buckets::Insert(pos, bounds, EDrawableType::Particle, reinterpret_cast<void*>(&gen), xb0_viewPlane, 0);
|
|
|
|
}
|
2022-02-27 21:58:27 +00:00
|
|
|
|
2022-03-07 03:07:00 +00:00
|
|
|
void CCubeRenderer::AddPlaneObject(void* obj, const zeus::CAABox& aabb, const zeus::CPlane& plane, s32 type) {
|
2022-02-27 20:12:02 +00:00
|
|
|
|
2022-03-07 03:07:00 +00:00
|
|
|
const auto closestPoint = aabb.closestPointAlongVector(xb0_viewPlane.normal());
|
|
|
|
const auto closestDist = xb0_viewPlane.pointToPlaneDist(closestPoint);
|
|
|
|
const auto furthestPoint = aabb.furthestPointAlongVector(xb0_viewPlane.normal());
|
|
|
|
const auto furthestDist = xb0_viewPlane.pointToPlaneDist(furthestPoint);
|
2022-02-27 20:12:02 +00:00
|
|
|
|
|
|
|
if (closestDist >= 0.f || furthestDist >= 0.f) {
|
2022-03-07 03:07:00 +00:00
|
|
|
const bool zOnly = plane.normal() == zeus::skUp;
|
|
|
|
const bool invertTest = zOnly ? CGraphics::g_GXModelView.origin.z() >= plane.d()
|
|
|
|
: plane.pointToPlaneDist(CGraphics::g_GXModelView.origin) >= 0.f;
|
2022-02-27 20:12:02 +00:00
|
|
|
Buckets::InsertPlaneObject(closestDist, furthestDist, aabb, invertTest, plane, zOnly, EDrawableType(type + 2), obj);
|
|
|
|
}
|
|
|
|
}
|
2022-02-27 21:58:27 +00:00
|
|
|
|
2022-03-07 03:07:00 +00:00
|
|
|
void CCubeRenderer::AddDrawable(void* obj, const zeus::CVector3f& pos, const zeus::CAABox& aabb, s32 mode,
|
2022-02-27 20:12:02 +00:00
|
|
|
IRenderer::EDrawableSorting sorting) {
|
|
|
|
if (sorting == EDrawableSorting::UnsortedCallback) {
|
|
|
|
xa8_drawableCallback(obj, xac_drawableCallbackUserData, mode);
|
|
|
|
} else {
|
|
|
|
Buckets::Insert(pos, aabb, EDrawableType(mode + 2), obj, xb0_viewPlane, 0);
|
|
|
|
}
|
|
|
|
}
|
2022-02-27 21:58:27 +00:00
|
|
|
|
2022-02-27 21:17:44 +00:00
|
|
|
void CCubeRenderer::SetDrawableCallback(IRenderer::TDrawableCallback cb, void* ctx) {
|
|
|
|
xa8_drawableCallback = cb;
|
|
|
|
xac_drawableCallbackUserData = ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCubeRenderer::SetWorldViewpoint(const zeus::CTransform& xf) {
|
|
|
|
CGraphics::SetViewPointMatrix(xf);
|
|
|
|
auto front = xf.frontVector();
|
|
|
|
xb0_viewPlane = zeus::CPlane(front, front.dot(xf.origin));
|
|
|
|
}
|
2022-02-27 21:58:27 +00:00
|
|
|
|
2022-02-27 21:17:44 +00:00
|
|
|
void CCubeRenderer::SetPerspective(float fovy, float aspect, float znear, float zfar) {
|
|
|
|
CGraphics::SetPerspective(fovy, aspect, znear, zfar);
|
|
|
|
}
|
2022-02-27 21:58:27 +00:00
|
|
|
|
2022-02-27 21:17:44 +00:00
|
|
|
void CCubeRenderer::SetPerspective(float fovy, float width, float height, float znear, float zfar) {
|
|
|
|
CGraphics::SetPerspective(fovy, width / height, znear, zfar);
|
|
|
|
}
|
|
|
|
|
2022-02-26 16:42:42 +00:00
|
|
|
std::pair<zeus::CVector2f, zeus::CVector2f> CCubeRenderer::SetViewportOrtho(bool centered, float znear, float zfar) {
|
2022-05-09 21:13:38 +00:00
|
|
|
auto left = static_cast<float>(centered ? CGraphics::GetViewportLeft() - CGraphics::GetViewportHalfWidth()
|
2022-03-06 04:50:54 +00:00
|
|
|
: CGraphics::GetViewportLeft());
|
2022-05-24 00:26:35 +00:00
|
|
|
auto bottom = static_cast<float>(centered ? CGraphics::GetViewportTop() - CGraphics::GetViewportHalfHeight()
|
|
|
|
: CGraphics::GetViewportTop());
|
2022-03-06 04:50:54 +00:00
|
|
|
auto right = static_cast<float>(CGraphics::GetViewportLeft() +
|
|
|
|
(centered ? CGraphics::GetViewportWidth() / 2 : CGraphics::GetViewportWidth()));
|
2022-05-24 00:26:35 +00:00
|
|
|
auto top = static_cast<float>(CGraphics::GetViewportTop() +
|
|
|
|
(centered ? CGraphics::GetViewportHeight() / 2 : CGraphics::GetViewportHeight()));
|
2022-03-06 04:50:54 +00:00
|
|
|
CGraphics::SetOrtho(left, right, top, bottom, znear, zfar);
|
|
|
|
CGraphics::SetViewPointMatrix({});
|
|
|
|
CGraphics::SetModelMatrix({});
|
2022-05-24 00:26:35 +00:00
|
|
|
return {{left, bottom}, {right, top}};
|
2022-02-26 16:42:42 +00:00
|
|
|
}
|
2022-02-27 21:58:27 +00:00
|
|
|
|
2022-02-27 21:17:44 +00:00
|
|
|
void CCubeRenderer::SetClippingPlanes(const zeus::CFrustum& frustum) { x44_frustumPlanes = frustum; }
|
2022-02-27 21:58:27 +00:00
|
|
|
|
2022-03-07 03:07:00 +00:00
|
|
|
void CCubeRenderer::SetViewport(s32 left, s32 bottom, s32 width, s32 height) {
|
2022-02-27 21:17:44 +00:00
|
|
|
CGraphics::SetViewport(left, bottom, width, height);
|
|
|
|
CGraphics::SetScissor(left, bottom, width, height);
|
|
|
|
}
|
2022-02-27 21:58:27 +00:00
|
|
|
|
2022-02-27 21:17:44 +00:00
|
|
|
void CCubeRenderer::BeginScene() {
|
|
|
|
CGraphics::SetUseVideoFilter(true);
|
|
|
|
CGraphics::SetViewport(0, 0, CGraphics::g_Viewport.x8_width, CGraphics::g_Viewport.xc_height);
|
|
|
|
|
|
|
|
CGraphics::SetClearColor(zeus::skClear);
|
|
|
|
CGraphics::SetCullMode(ERglCullMode::Front);
|
|
|
|
CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, true);
|
|
|
|
CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::InvSrcAlpha,
|
|
|
|
ERglLogicOp::Clear);
|
|
|
|
CGraphics::SetPerspective(75.f, CGraphics::g_Viewport.x8_width / CGraphics::g_Viewport.xc_height, 1.f, 4096.f);
|
|
|
|
CGraphics::SetModelMatrix(zeus::CTransform());
|
|
|
|
if (x310_phazonSuitMaskCountdown != 0) {
|
|
|
|
--x310_phazonSuitMaskCountdown;
|
|
|
|
if (x310_phazonSuitMaskCountdown == 0) {
|
|
|
|
x314_phazonSuitMask.reset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-02 00:47:45 +00:00
|
|
|
x318_27_currentRGBA6 = x318_26_requestRGBA6;
|
2022-02-27 21:17:44 +00:00
|
|
|
if (!x318_31_persistRGBA6) {
|
|
|
|
x318_26_requestRGBA6 = false;
|
|
|
|
}
|
|
|
|
|
2022-07-02 00:47:45 +00:00
|
|
|
// GXSetPixelFmt(x318_27_currentRGBA6, GX_ZC_LINEAR);
|
2022-03-12 15:47:20 +00:00
|
|
|
GXSetAlphaUpdate(true);
|
|
|
|
GXSetDstAlpha(true, 0.f);
|
2022-02-27 21:17:44 +00:00
|
|
|
CGraphics::BeginScene();
|
|
|
|
}
|
2022-02-27 21:58:27 +00:00
|
|
|
|
2022-02-27 21:17:44 +00:00
|
|
|
void CCubeRenderer::EndScene() {
|
|
|
|
x318_31_persistRGBA6 = !CGraphics::g_IsBeginSceneClearFb;
|
|
|
|
CGraphics::EndScene();
|
|
|
|
|
|
|
|
if (x2dc_reflectionAge < 2) {
|
|
|
|
++x2dc_reflectionAge;
|
|
|
|
} else {
|
|
|
|
x14c_reflectionTex.reset();
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-03-07 03:07:00 +00:00
|
|
|
void CCubeRenderer::SetDebugOption(IRenderer::EDebugOption option, s32 value) {
|
2022-02-27 21:17:44 +00:00
|
|
|
if (option == EDebugOption::PVSState) {
|
2022-03-08 23:35:40 +00:00
|
|
|
if (xc8_pvs) {
|
|
|
|
xc8_pvs->SetState(EPVSVisSetState(value));
|
|
|
|
}
|
2022-02-27 21:58:27 +00:00
|
|
|
} else if (option == EDebugOption::PVSMode) {
|
2022-02-27 21:17:44 +00:00
|
|
|
xc0_pvsMode = EPVSMode(value);
|
2022-02-27 21:58:27 +00:00
|
|
|
} else if (option == EDebugOption::FogDisabled) {
|
2022-02-27 21:17:44 +00:00
|
|
|
x318_28_disableFog = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-06 04:50:54 +00:00
|
|
|
void CCubeRenderer::BeginPrimitive(IRenderer::EPrimitiveType type, s32 nverts) {
|
2022-03-23 05:35:13 +00:00
|
|
|
constexpr std::array vtxDescList{
|
2022-07-29 20:16:55 +00:00
|
|
|
GXVtxDescList{GX_VA_POS, GX_DIRECT},
|
|
|
|
GXVtxDescList{GX_VA_NRM, GX_DIRECT},
|
|
|
|
GXVtxDescList{GX_VA_CLR0, GX_DIRECT},
|
|
|
|
GXVtxDescList{GX_VA_NULL, GX_NONE},
|
2022-03-23 05:35:13 +00:00
|
|
|
};
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetChanCtrl(CGX::EChannelId::Channel0, false, GX_SRC_REG, GX_SRC_VTX, {}, GX_DF_NONE, GX_AF_NONE);
|
2022-03-23 05:35:13 +00:00
|
|
|
CGX::SetNumChans(1);
|
|
|
|
CGX::SetNumTexGens(0);
|
|
|
|
CGX::SetNumTevStages(1);
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
|
|
|
|
CGX::SetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_RASC);
|
|
|
|
CGX::SetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_RASA);
|
|
|
|
CGX::SetStandardTevColorAlphaOp(GX_TEVSTAGE0);
|
2022-03-06 04:50:54 +00:00
|
|
|
x18_primVertCount = nverts;
|
2022-03-23 05:35:13 +00:00
|
|
|
CGX::SetVtxDescv(vtxDescList.data());
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::Begin(GXPrimitive(type), GX_VTXFMT0, nverts);
|
2022-03-06 04:50:54 +00:00
|
|
|
}
|
2022-03-12 15:47:20 +00:00
|
|
|
|
2022-03-06 04:50:54 +00:00
|
|
|
void CCubeRenderer::BeginLines(s32 nverts) { BeginPrimitive(EPrimitiveType::Lines, nverts); }
|
2022-03-12 15:47:20 +00:00
|
|
|
|
2022-03-06 04:50:54 +00:00
|
|
|
void CCubeRenderer::BeginLineStrip(s32 nverts) { BeginPrimitive(EPrimitiveType::LineStrip, nverts); }
|
2022-03-12 15:47:20 +00:00
|
|
|
|
2022-03-06 04:50:54 +00:00
|
|
|
void CCubeRenderer::BeginTriangles(s32 nverts) { BeginPrimitive(EPrimitiveType::Triangles, nverts); }
|
2022-03-12 15:47:20 +00:00
|
|
|
|
2022-03-06 04:50:54 +00:00
|
|
|
void CCubeRenderer::BeginTriangleStrip(s32 nverts) { BeginPrimitive(EPrimitiveType::TriangleStrip, nverts); }
|
2022-03-12 15:47:20 +00:00
|
|
|
|
2022-03-06 04:50:54 +00:00
|
|
|
void CCubeRenderer::BeginTriangleFan(s32 nverts) { BeginPrimitive(EPrimitiveType::TriangleFan, nverts); }
|
2022-03-12 15:47:20 +00:00
|
|
|
|
2022-03-06 04:50:54 +00:00
|
|
|
void CCubeRenderer::PrimVertex(const zeus::CVector3f& vertex) {
|
|
|
|
--x18_primVertCount;
|
2022-03-23 05:35:13 +00:00
|
|
|
GXPosition3f32(vertex);
|
|
|
|
GXNormal3f32(x2e4_primNormal);
|
|
|
|
GXColor4f32(x2e0_primColor);
|
2022-03-06 04:50:54 +00:00
|
|
|
}
|
2022-03-12 15:47:20 +00:00
|
|
|
|
2022-03-06 04:50:54 +00:00
|
|
|
void CCubeRenderer::PrimNormal(const zeus::CVector3f& normal) { x2e4_primNormal = normal; }
|
2022-03-12 15:47:20 +00:00
|
|
|
|
2022-03-06 04:50:54 +00:00
|
|
|
void CCubeRenderer::PrimColor(float r, float g, float b, float a) { PrimColor({r, g, b, a}); }
|
2022-03-12 15:47:20 +00:00
|
|
|
|
2022-03-06 04:50:54 +00:00
|
|
|
void CCubeRenderer::PrimColor(const zeus::CColor& color) { x2e0_primColor = color; }
|
2022-03-12 15:47:20 +00:00
|
|
|
|
2022-03-06 04:50:54 +00:00
|
|
|
void CCubeRenderer::EndPrimitive() {
|
|
|
|
while (x18_primVertCount > 0) {
|
|
|
|
PrimVertex(zeus::skZero3f);
|
|
|
|
}
|
2022-03-23 05:35:13 +00:00
|
|
|
CGX::End();
|
2022-03-06 04:50:54 +00:00
|
|
|
}
|
2022-03-12 15:47:20 +00:00
|
|
|
|
2022-03-06 04:50:54 +00:00
|
|
|
void CCubeRenderer::SetAmbientColor(const zeus::CColor& color) { CGraphics::SetAmbientColor(color); }
|
2022-03-12 15:47:20 +00:00
|
|
|
|
2022-03-07 03:07:00 +00:00
|
|
|
void CCubeRenderer::DrawString(const char* string, s32 x, s32 y) { x10_font.DrawString(string, x, y, zeus::skWhite); }
|
2022-02-27 02:18:58 +00:00
|
|
|
|
|
|
|
u32 CCubeRenderer::GetFPS() { return CGraphics::GetFPS(); }
|
2022-03-12 15:47:20 +00:00
|
|
|
|
|
|
|
void CCubeRenderer::CacheReflection(IRenderer::TReflectionCallback cb, void* ctx, bool clearAfter) {
|
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCubeRenderer::DrawSpaceWarp(const zeus::CVector3f& pt, float strength) {
|
2022-07-02 00:47:45 +00:00
|
|
|
if (pt.z() < 1.f) {
|
|
|
|
ReallyDrawSpaceWarp(pt, strength);
|
|
|
|
}
|
2022-03-12 15:47:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCubeRenderer::DrawThermalModel(CModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol,
|
|
|
|
TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags) {
|
|
|
|
model.UpdateLastFrame();
|
2022-05-13 23:40:19 +00:00
|
|
|
DoThermalModelDraw(model.GetInstance(), multCol, addCol, positions, normals, flags);
|
2022-03-12 15:47:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCubeRenderer::DrawModelDisintegrate(CModel& model, CTexture& tex, const zeus::CColor& color,
|
|
|
|
TConstVectorRef positions, TConstVectorRef normals, float t) {
|
2022-07-29 20:16:55 +00:00
|
|
|
tex.Load(GX_TEXMAP0, EClampMode::Clamp);
|
2022-03-12 15:47:20 +00:00
|
|
|
CGX::SetNumIndStages(0);
|
|
|
|
CGX::SetNumTevStages(2);
|
|
|
|
CGX::SetNumTexGens(2);
|
|
|
|
CGX::SetNumChans(0);
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
|
|
|
|
CGX::SetStandardTevColorAlphaOp(GX_TEVSTAGE0);
|
|
|
|
CGX::SetStandardTevColorAlphaOp(GX_TEVSTAGE1);
|
|
|
|
CGX::SetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_TEXC);
|
|
|
|
CGX::SetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA);
|
|
|
|
CGX::SetTevColorIn(GX_TEVSTAGE1, GX_CC_ZERO, GX_CC_TEXC, GX_CC_CPREV, GX_CC_KONST);
|
|
|
|
CGX::SetTevAlphaIn(GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_TEXA, GX_CA_APREV, GX_CA_ZERO);
|
|
|
|
CGX::SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
|
|
|
|
CGX::SetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD1, GX_TEXMAP0, GX_COLOR_NULL);
|
|
|
|
CGX::SetTevKColorSel(GX_TEVSTAGE1, GX_TEV_KCSEL_K0);
|
|
|
|
CGX::SetTevKColor(GX_KCOLOR0, color);
|
2022-07-02 17:18:54 +00:00
|
|
|
const auto bounds = model.GetInstance().GetBounds();
|
|
|
|
const auto rotation = zeus::CTransform::RotateX(zeus::degToRad(-45.f));
|
|
|
|
const auto transformedBounds = bounds.getTransformedAABox(rotation);
|
|
|
|
const auto xf = zeus::CTransform::Scale(5.f / (transformedBounds.max - transformedBounds.min)) *
|
|
|
|
zeus::CTransform::Translate(-transformedBounds.min) * rotation;
|
|
|
|
const zeus::CTransform ptTex1{
|
|
|
|
zeus::CMatrix3f{
|
|
|
|
1.f, 1.f, 0.f,
|
|
|
|
0.f, 0.f, 1.f,
|
|
|
|
0.f, 0.f, 0.f,
|
|
|
|
},
|
|
|
|
zeus::CVector3f{t * -0.85f - 0.15f, -(1.f - t) * 6.f + 1.f, 1.f},
|
|
|
|
};
|
|
|
|
const zeus::CTransform ptTex0{
|
|
|
|
zeus::CMatrix3f{
|
|
|
|
1.f, 1.f, 0.f,
|
|
|
|
0.f, 0.f, 1.f,
|
|
|
|
0.f, 0.f, 0.f,
|
|
|
|
},
|
|
|
|
zeus::CVector3f{t, ptTex1.origin.y(), 1.f},
|
|
|
|
};
|
2022-07-29 20:16:55 +00:00
|
|
|
GXLoadTexMtxImm(&xf, GX_TEXMTX0, GX_MTX3x4);
|
|
|
|
GXLoadTexMtxImm(&ptTex0, GX_PTTEXMTX0, GX_MTX3x4);
|
|
|
|
GXLoadTexMtxImm(&ptTex1, GX_PTTEXMTX1, GX_MTX3x4);
|
|
|
|
CGX::SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX3x4, GX_TG_POS, GX_TEXMTX0, false, GX_PTTEXMTX0);
|
|
|
|
CGX::SetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX3x4, GX_TG_POS, GX_TEXMTX0, false, GX_PTTEXMTX1);
|
|
|
|
CGX::SetAlphaCompare(GX_GREATER, 0, GX_AOP_AND, GX_ALWAYS, 0);
|
|
|
|
CGX::SetZMode(true, GX_LEQUAL, true);
|
2022-07-02 17:18:54 +00:00
|
|
|
model.UpdateLastFrame();
|
|
|
|
model.GetInstance().DrawFlat(positions, normals, ESurfaceSelection::All);
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0);
|
2022-03-12 15:47:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCubeRenderer::DrawModelFlat(CModel& model, const CModelFlags& flags, bool unsortedOnly, TConstVectorRef positions,
|
|
|
|
TConstVectorRef normals) {
|
|
|
|
if (flags.x0_blendMode >= 7) {
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_ONE, GX_LO_CLEAR);
|
2022-03-12 15:47:20 +00:00
|
|
|
} else if (flags.x0_blendMode >= 5) {
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
|
2022-03-12 15:47:20 +00:00
|
|
|
} else {
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetBlendMode(GX_BM_BLEND, GX_BL_ONE, GX_BL_ZERO, GX_LO_CLEAR);
|
2022-03-12 15:47:20 +00:00
|
|
|
}
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetZMode(true, flags.x2_flags & CModelFlagBits::DepthTest ? GX_LEQUAL : GX_ALWAYS,
|
2022-03-12 15:47:20 +00:00
|
|
|
flags.x2_flags.IsSet(CModelFlagBits::DepthUpdate));
|
|
|
|
CGX::SetNumTevStages(1);
|
|
|
|
CGX::SetNumTexGens(1);
|
|
|
|
CGX::SetNumChans(0);
|
|
|
|
CGX::SetNumIndStages(0);
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0);
|
|
|
|
CGX::SetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_KONST);
|
|
|
|
CGX::SetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_KONST);
|
|
|
|
CGX::SetTevKColor(GX_KCOLOR0, flags.x4_color);
|
|
|
|
CGX::SetTevKColorSel(GX_TEVSTAGE0, GX_TEV_KCSEL_K0);
|
|
|
|
CGX::SetTevKAlphaSel(GX_TEVSTAGE0, GX_TEV_KASEL_K0_A);
|
|
|
|
CGX::SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL);
|
|
|
|
CGX::SetStandardTevColorAlphaOp(GX_TEVSTAGE0);
|
|
|
|
CGX::SetTevDirect(GX_TEVSTAGE0);
|
|
|
|
CGX::SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_POS, GX_IDENTITY, false, GX_PTIDENTITY);
|
2022-03-12 15:47:20 +00:00
|
|
|
model.UpdateLastFrame();
|
|
|
|
model.GetInstance().DrawFlat(positions, normals, unsortedOnly ? ESurfaceSelection::Unsorted : ESurfaceSelection::All);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCubeRenderer::SetWireframeFlags(s32 flags) {
|
2022-07-02 00:47:45 +00:00
|
|
|
CCubeModel::SetModelWireframe((flags & 0x1) != 0);
|
|
|
|
x318_25_drawWireframe = (flags & 0x2) != 0;
|
2022-03-12 15:47:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCubeRenderer::SetWorldFog(ERglFogMode mode, float startz, float endz, const zeus::CColor& color) {
|
2022-03-14 23:12:18 +00:00
|
|
|
CGraphics::SetFog(x318_28_disableFog ? ERglFogMode::None : mode, startz, endz, color);
|
2022-03-12 15:47:20 +00:00
|
|
|
}
|
|
|
|
|
2022-02-26 16:42:42 +00:00
|
|
|
void CCubeRenderer::RenderFogVolume(const zeus::CColor& color, const zeus::CAABox& aabb,
|
2022-03-12 15:47:20 +00:00
|
|
|
const TLockedToken<CModel>* model, const CSkinnedModel* sModel) {
|
2022-07-02 00:47:45 +00:00
|
|
|
if (!x318_28_disableFog) {
|
|
|
|
x2ac_fogVolumes.emplace_back(CGraphics::g_GXModelMatrix, color, aabb, model, sModel);
|
|
|
|
}
|
2022-03-12 15:47:20 +00:00
|
|
|
}
|
2022-02-27 21:58:27 +00:00
|
|
|
|
2022-03-12 15:47:20 +00:00
|
|
|
void CCubeRenderer::SetThermal(bool thermal, float level, const zeus::CColor& color) {
|
2022-05-13 23:40:19 +00:00
|
|
|
x318_29_thermalVisor = thermal;
|
|
|
|
x2f0_thermalVisorLevel = level;
|
|
|
|
x2f4_thermColor = color;
|
|
|
|
CDecal::SetMoveRedToAlphaBuffer(false);
|
|
|
|
CElementGen::SetMoveRedToAlphaBuffer(false);
|
2022-03-12 15:47:20 +00:00
|
|
|
}
|
|
|
|
|
2022-03-19 17:30:25 +00:00
|
|
|
void CCubeRenderer::SetThermalColdScale(float scale) { x2f8_thermColdScale = zeus::clamp(0.f, scale, 1.f); }
|
2022-03-12 15:47:20 +00:00
|
|
|
|
|
|
|
void CCubeRenderer::DoThermalBlendCold() {
|
2022-05-24 00:26:35 +00:00
|
|
|
SCOPED_GRAPHICS_DEBUG_GROUP("CCubeRenderer::DoThermalBlendCold", zeus::skBlue);
|
|
|
|
|
2022-05-13 23:40:19 +00:00
|
|
|
// Capture EFB
|
|
|
|
x318_26_requestRGBA6 = true;
|
|
|
|
GXSetAlphaUpdate(true);
|
|
|
|
GXSetDstAlpha(false, 0);
|
|
|
|
const auto height = CGraphics::GetViewportHeight();
|
|
|
|
const auto width = CGraphics::GetViewportWidth();
|
|
|
|
const auto top = CGraphics::GetViewportTop();
|
|
|
|
const auto left = CGraphics::GetViewportLeft();
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetZMode(true, GX_LEQUAL, false);
|
2022-08-09 06:10:51 +00:00
|
|
|
GXSetTexCopySrc(left, top, width, height);
|
|
|
|
GXSetTexCopyDst(width, height, GX_TF_I4, false);
|
|
|
|
GXCopyTex(CGraphics::sSpareTextureData, true);
|
|
|
|
CGraphics::LoadDolphinSpareTexture(width, height, GX_TF_I4, nullptr, GX_TEXMAP7);
|
2022-05-13 23:40:19 +00:00
|
|
|
|
|
|
|
// Upload random static texture (game reads from .text)
|
|
|
|
const u8* buf = CDvdFile::GetDolBuf() + 0x4f60;
|
|
|
|
u8* out = m_thermalRandomStatic.Lock();
|
|
|
|
memcpy(out, buf + ROUND_UP_32(x2a8_thermalRand.Next()), m_thermalRandomStatic.GetMemoryAllocated());
|
|
|
|
m_thermalRandomStatic.UnLock();
|
2022-07-29 20:16:55 +00:00
|
|
|
m_thermalRandomStatic.Load(GX_TEXMAP0, EClampMode::Clamp);
|
|
|
|
m_thermalRandomStatic.Load(GX_TEXMAP1, EClampMode::Clamp);
|
2022-05-13 23:40:19 +00:00
|
|
|
|
|
|
|
// Configure indirect texturing
|
|
|
|
const float level = std::clamp(x2f0_thermalVisorLevel * 0.5f, 0.f, 0.5f);
|
|
|
|
const aurora::Mat3x2<float> mtx{
|
|
|
|
aurora::Vec2{(1.f - level) * 0.1f, 0.f},
|
|
|
|
aurora::Vec2{0.f, 0.f},
|
|
|
|
aurora::Vec2{0.f, level},
|
|
|
|
};
|
2022-07-29 20:16:55 +00:00
|
|
|
GXSetIndTexMtx(GX_ITM_0, &mtx, -2);
|
|
|
|
CGX::SetTevIndirect(GX_TEVSTAGE0, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_STU, GX_ITM_0, GX_ITW_OFF, GX_ITW_OFF, false,
|
|
|
|
false, GX_ITBA_OFF);
|
|
|
|
GXSetIndTexOrder(GX_INDTEXSTAGE0, GX_TEXCOORD0, GX_TEXMAP0);
|
2022-05-13 23:40:19 +00:00
|
|
|
|
|
|
|
// Configure register colors
|
|
|
|
const auto color0 = zeus::CColor::lerp(x2f4_thermColor, zeus::skWhite, x2f8_thermColdScale);
|
|
|
|
const float bAlpha = x2f8_thermColdScale < 0.5f ? x2f8_thermColdScale * 2.f : 1.f;
|
|
|
|
const float bFac = (1.f - bAlpha) / 8.f;
|
|
|
|
const zeus::CColor color1{bFac, bAlpha};
|
|
|
|
float cFac;
|
|
|
|
if (x2f8_thermColdScale < 0.25f) {
|
|
|
|
cFac = 0.f;
|
|
|
|
} else if (x2f8_thermColdScale >= 1.f) {
|
|
|
|
cFac = 1.f;
|
|
|
|
} else {
|
|
|
|
cFac = (x2f8_thermColdScale - 0.25f) * 4.f / 3.f;
|
|
|
|
}
|
|
|
|
const zeus::CColor color2{cFac, cFac};
|
2022-07-29 20:16:55 +00:00
|
|
|
GXSetTevColor(GX_TEVREG0, to_gx_color(color0));
|
|
|
|
GXSetTevColor(GX_TEVREG1, to_gx_color(color1));
|
|
|
|
GXSetTevColor(GX_TEVREG2, to_gx_color(color2));
|
2022-05-13 23:40:19 +00:00
|
|
|
|
|
|
|
// Configure TEV stage 0
|
2022-07-29 20:16:55 +00:00
|
|
|
GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP1);
|
|
|
|
CGX::SetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_TEXC, GX_CC_C0, GX_CC_C2);
|
|
|
|
CGX::SetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_TEXA, GX_CA_A1, GX_CA_A2);
|
|
|
|
CGX::SetStandardTevColorAlphaOp(GX_TEVSTAGE0);
|
|
|
|
CGX::SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP7, GX_COLOR_NULL);
|
2022-05-13 23:40:19 +00:00
|
|
|
|
|
|
|
// Configure TEV stage 1
|
2022-07-29 20:16:55 +00:00
|
|
|
GXSetTevSwapMode(GX_TEVSTAGE1, GX_TEV_SWAP0, GX_TEV_SWAP1);
|
|
|
|
CGX::SetTevColorIn(GX_TEVSTAGE1, GX_CC_ZERO, GX_CC_TEXC, GX_CC_C1, GX_CC_CPREV);
|
|
|
|
CGX::SetTevColorOp(GX_TEVSTAGE1, GX_TEV_SUB, GX_TB_ZERO, GX_CS_SCALE_1, true, GX_TEVPREV);
|
|
|
|
CGX::SetTevAlphaIn(GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_A1, GX_CA_TEXA, GX_CA_APREV);
|
|
|
|
CGX::SetTevAlphaOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_4, true, GX_TEVPREV);
|
|
|
|
CGX::SetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD0, GX_TEXMAP1, GX_COLOR_NULL);
|
2022-05-13 23:40:19 +00:00
|
|
|
|
|
|
|
// Configure everything else
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX3x4, GX_TG_TEX0, GX_IDENTITY, false, GX_PTIDENTITY);
|
|
|
|
CGX::SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0);
|
2022-05-13 23:40:19 +00:00
|
|
|
CGX::SetNumTevStages(2);
|
|
|
|
CGX::SetNumTexGens(1);
|
|
|
|
CGX::SetNumChans(0);
|
|
|
|
CGX::SetNumIndStages(1);
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetZMode(false, GX_ALWAYS, false);
|
2022-05-13 23:40:19 +00:00
|
|
|
constexpr std::array vtxDescList{
|
2022-07-29 20:16:55 +00:00
|
|
|
GXVtxDescList{GX_VA_POS, GX_DIRECT},
|
|
|
|
GXVtxDescList{GX_VA_TEX0, GX_DIRECT},
|
|
|
|
GXVtxDescList{GX_VA_NULL, GX_NONE},
|
2022-05-13 23:40:19 +00:00
|
|
|
};
|
|
|
|
CGX::SetVtxDescv(vtxDescList.data());
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetBlendMode(GX_BM_NONE, GX_BL_ONE, GX_BL_ZERO, GX_LO_CLEAR);
|
2022-05-13 23:40:19 +00:00
|
|
|
|
|
|
|
// Backup & set viewport/projection
|
|
|
|
const auto backupViewMatrix = CGraphics::g_ViewMatrix;
|
|
|
|
const auto backupProjectionState = CGraphics::GetProjectionState();
|
|
|
|
CGraphics::SetOrtho(0.f, static_cast<float>(width), 0.f, static_cast<float>(height), -4096.f, 4096.f);
|
|
|
|
CGraphics::SetViewPointMatrix({});
|
|
|
|
CGraphics::SetModelMatrix({});
|
|
|
|
GXPixModeSync();
|
|
|
|
|
|
|
|
// Draw
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::Begin(GX_TRIANGLEFAN, GX_VTXFMT0, 4);
|
2022-05-13 23:40:19 +00:00
|
|
|
GXPosition3f32(0.f, 0.5f, 0.f);
|
|
|
|
GXTexCoord2f32(0.f, 0.f);
|
|
|
|
GXPosition3f32(0.f, 0.5f, static_cast<float>(height));
|
|
|
|
GXTexCoord2f32(0.f, 1.f);
|
|
|
|
GXPosition3f32(static_cast<float>(width), 0.5f, static_cast<float>(height));
|
|
|
|
GXTexCoord2f32(1.f, 1.f);
|
|
|
|
GXPosition3f32(static_cast<float>(width), 0.5f, 0.f);
|
|
|
|
GXTexCoord2f32(1.f, 0.f);
|
|
|
|
CGX::End();
|
|
|
|
|
|
|
|
// Cleanup
|
2022-07-29 20:16:55 +00:00
|
|
|
GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0);
|
|
|
|
GXSetTevSwapMode(GX_TEVSTAGE1, GX_TEV_SWAP0, GX_TEV_SWAP0);
|
2022-05-13 23:40:19 +00:00
|
|
|
CGX::SetNumIndStages(0);
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetTevDirect(GX_TEVSTAGE0);
|
2022-05-13 23:40:19 +00:00
|
|
|
GXSetDstAlpha(false, 255);
|
|
|
|
CGraphics::SetProjectionState(backupProjectionState);
|
|
|
|
CGraphics::SetViewPointMatrix(backupViewMatrix);
|
|
|
|
CDecal::SetMoveRedToAlphaBuffer(true);
|
|
|
|
CElementGen::SetMoveRedToAlphaBuffer(true);
|
2022-03-12 15:47:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCubeRenderer::DoThermalBlendHot() {
|
2022-05-24 00:26:35 +00:00
|
|
|
SCOPED_GRAPHICS_DEBUG_GROUP("CCubeRenderer::DoThermalBlendHot", zeus::skRed);
|
2022-05-13 23:40:19 +00:00
|
|
|
|
|
|
|
GXSetAlphaUpdate(false);
|
|
|
|
GXSetDstAlpha(true, 0);
|
|
|
|
const auto height = CGraphics::GetViewportHeight();
|
|
|
|
const auto width = CGraphics::GetViewportWidth();
|
|
|
|
const auto top = CGraphics::GetViewportTop();
|
|
|
|
const auto left = CGraphics::GetViewportLeft();
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetZMode(true, GX_LEQUAL, true);
|
2022-08-09 06:10:51 +00:00
|
|
|
GXSetTexCopySrc(left, top, width, height);
|
|
|
|
GXSetTexCopyDst(width, height, GX_TF_I4, false);
|
|
|
|
GXCopyTex(CGraphics::sSpareTextureData, false);
|
2022-05-13 23:40:19 +00:00
|
|
|
x288_thermoPalette.Load();
|
2022-08-09 06:10:51 +00:00
|
|
|
CGraphics::LoadDolphinSpareTexture(width, height, GX_TF_C4, GX_TLUT0, nullptr, GX_TEXMAP7);
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_TEXA, GX_CC_TEXC, GX_CC_ZERO);
|
|
|
|
CGX::SetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA);
|
|
|
|
CGX::SetStandardTevColorAlphaOp(GX_TEVSTAGE0);
|
|
|
|
CGX::SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP7, GX_COLOR_NULL);
|
|
|
|
CGX::SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX3x4, GX_TG_TEX0, GX_IDENTITY, false, GX_PTIDENTITY);
|
|
|
|
CGX::SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0);
|
2022-05-13 23:40:19 +00:00
|
|
|
CGX::SetNumTevStages(1);
|
|
|
|
CGX::SetNumTexGens(1);
|
|
|
|
CGX::SetNumChans(0);
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetZMode(false, GX_LEQUAL, false);
|
2022-05-13 23:40:19 +00:00
|
|
|
constexpr std::array vtxDescList{
|
2022-07-29 20:16:55 +00:00
|
|
|
GXVtxDescList{GX_VA_POS, GX_DIRECT},
|
|
|
|
GXVtxDescList{GX_VA_TEX0, GX_DIRECT},
|
|
|
|
GXVtxDescList{GX_VA_NULL, GX_NONE},
|
2022-05-13 23:40:19 +00:00
|
|
|
};
|
|
|
|
CGX::SetVtxDescv(vtxDescList.data());
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetBlendMode(GX_BM_BLEND, GX_BL_DSTALPHA, GX_BL_INVDSTALPHA, GX_LO_CLEAR);
|
2022-05-13 23:40:19 +00:00
|
|
|
|
|
|
|
// Backup & set viewport/projection
|
|
|
|
const auto backupViewMatrix = CGraphics::g_ViewMatrix;
|
|
|
|
const auto backupProjectionState = CGraphics::GetProjectionState();
|
|
|
|
CGraphics::SetOrtho(0.f, static_cast<float>(width), 0.f, static_cast<float>(height), -4096.f, 4096.f);
|
|
|
|
CGraphics::SetViewPointMatrix({});
|
|
|
|
CGraphics::SetModelMatrix({});
|
|
|
|
GXPixModeSync();
|
|
|
|
|
|
|
|
// Draw
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::Begin(GX_TRIANGLEFAN, GX_VTXFMT0, 4);
|
2022-05-13 23:40:19 +00:00
|
|
|
GXPosition3f32(0.f, 0.5f, 0.f);
|
|
|
|
GXTexCoord2f32(0.f, 0.f);
|
|
|
|
GXPosition3f32(0.f, 0.5f, static_cast<float>(height));
|
|
|
|
GXTexCoord2f32(0.f, 1.f);
|
|
|
|
GXPosition3f32(static_cast<float>(width), 0.5f, static_cast<float>(height));
|
|
|
|
GXTexCoord2f32(1.f, 1.f);
|
|
|
|
GXPosition3f32(static_cast<float>(width), 0.5f, 0.f);
|
|
|
|
GXTexCoord2f32(1.f, 0.f);
|
|
|
|
CGX::End();
|
|
|
|
|
2022-05-24 00:26:35 +00:00
|
|
|
// Cleanup
|
|
|
|
CGX::SetNumIndStages(0);
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetTevDirect(GX_TEVSTAGE0);
|
2022-05-24 00:26:35 +00:00
|
|
|
GXSetAlphaUpdate(true);
|
|
|
|
CGraphics::SetProjectionState(backupProjectionState);
|
|
|
|
CGraphics::SetViewPointMatrix(backupViewMatrix);
|
|
|
|
CDecal::SetMoveRedToAlphaBuffer(false);
|
|
|
|
CElementGen::SetMoveRedToAlphaBuffer(false);
|
2022-03-12 15:47:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
u32 CCubeRenderer::GetStaticWorldDataSize() {
|
|
|
|
// TODO
|
|
|
|
return 0;
|
2022-02-27 21:17:44 +00:00
|
|
|
}
|
2022-02-27 21:58:27 +00:00
|
|
|
|
2022-07-29 20:16:55 +00:00
|
|
|
void CCubeRenderer::SetGXRegister1Color(const zeus::CColor& color) { GXSetTevColor(GX_TEVREG1, to_gx_color(color)); }
|
2022-03-12 15:47:20 +00:00
|
|
|
|
2022-02-27 21:17:44 +00:00
|
|
|
void CCubeRenderer::SetWorldLightFadeLevel(float level) { x2fc_tevReg1Color = zeus::CColor(level, level, level, 1.f); }
|
2022-02-27 21:58:27 +00:00
|
|
|
|
2022-03-12 15:47:20 +00:00
|
|
|
void CCubeRenderer::PrepareDynamicLights(const std::vector<CLight>& lights) {
|
2022-03-13 19:14:11 +00:00
|
|
|
x300_dynamicLights = lights;
|
|
|
|
|
|
|
|
for (CAreaListItem& area : x1c_areaListItems) {
|
|
|
|
if (const CAreaRenderOctTree* arot = area.x4_octTree) {
|
|
|
|
area.x1c_lightOctreeWords.clear();
|
|
|
|
area.x1c_lightOctreeWords.resize(arot->x14_bitmapWordCount * lights.size());
|
|
|
|
u32* wordPtr = area.x1c_lightOctreeWords.data();
|
|
|
|
for (const CLight& light : lights) {
|
|
|
|
float radius = light.GetRadius();
|
|
|
|
zeus::CVector3f vMin = light.GetPosition() - radius;
|
|
|
|
zeus::CVector3f vMax = light.GetPosition() + radius;
|
|
|
|
zeus::CAABox aabb(vMin, vMax);
|
|
|
|
arot->FindOverlappingModels(wordPtr, aabb);
|
|
|
|
wordPtr += arot->x14_bitmapWordCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-03-12 15:47:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCubeRenderer::AllocatePhazonSuitMaskTexture() {
|
2022-07-02 00:47:45 +00:00
|
|
|
x318_26_requestRGBA6 = true;
|
|
|
|
if (!x314_phazonSuitMask) {
|
|
|
|
x314_phazonSuitMask = std::make_unique<CTexture>(ETexelFormat::I8, CGraphics::GetViewportWidth() / 4,
|
|
|
|
CGraphics::GetViewportHeight() / 4, 1, "Phazon Suit Mask"sv);
|
|
|
|
}
|
|
|
|
x310_phazonSuitMaskCountdown = 2;
|
2022-03-12 15:47:20 +00:00
|
|
|
}
|
2022-03-08 22:21:15 +00:00
|
|
|
|
2022-02-26 16:42:42 +00:00
|
|
|
void CCubeRenderer::DrawPhazonSuitIndirectEffect(const zeus::CColor& nonIndirectMod,
|
|
|
|
const TLockedToken<CTexture>& indTex, const zeus::CColor& indirectMod,
|
2022-03-08 22:21:15 +00:00
|
|
|
float blurRadius, float scale, float offX, float offY) {
|
2022-07-02 00:47:45 +00:00
|
|
|
if (x318_27_currentRGBA6 && x310_phazonSuitMaskCountdown != 0) {
|
|
|
|
const auto backupViewMatrix = CGraphics::g_ViewMatrix;
|
|
|
|
const auto backupProjectionState = CGraphics::GetProjectionState();
|
|
|
|
if (!x314_phazonSuitMask || x314_phazonSuitMask->GetWidth() != CGraphics::GetViewportWidth() / 4 ||
|
|
|
|
x314_phazonSuitMask->GetHeight() != CGraphics::GetViewportHeight() / 4) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
DoPhazonSuitIndirectAlphaBlur(blurRadius, blurRadius);
|
|
|
|
// TODO copy into x314_phazonSuitMask
|
|
|
|
if (indTex) {
|
|
|
|
ReallyDrawPhazonSuitIndirectEffect(zeus::skWhite, *x314_phazonSuitMask, const_cast<CTexture&>(*indTex),
|
|
|
|
indirectMod, scale, offX, offY);
|
|
|
|
} else {
|
|
|
|
ReallyDrawPhazonSuitEffect(nonIndirectMod, *x314_phazonSuitMask);
|
|
|
|
}
|
|
|
|
// TODO unlock x314
|
|
|
|
CGraphics::SetViewPointMatrix(backupViewMatrix);
|
|
|
|
CGraphics::SetProjectionState(backupProjectionState);
|
|
|
|
x310_phazonSuitMaskCountdown = 2;
|
|
|
|
}
|
2022-03-12 15:47:20 +00:00
|
|
|
GXSetDstAlpha(false, 0.f);
|
2022-03-08 22:21:15 +00:00
|
|
|
}
|
|
|
|
|
2022-03-12 15:47:20 +00:00
|
|
|
void CCubeRenderer::DrawXRayOutline(const zeus::CAABox& aabb) {
|
|
|
|
// TODO
|
|
|
|
}
|
2022-03-06 04:50:54 +00:00
|
|
|
|
|
|
|
std::list<CCubeRenderer::CAreaListItem>::iterator
|
|
|
|
CCubeRenderer::FindStaticGeometry(const std::vector<CMetroidModelInstance>* geometry) {
|
|
|
|
return std::find_if(x1c_areaListItems.begin(), x1c_areaListItems.end(),
|
|
|
|
[&](const CAreaListItem& item) { return item.x0_geometry == geometry; });
|
|
|
|
}
|
|
|
|
|
2022-07-02 00:47:45 +00:00
|
|
|
void CCubeRenderer::FindOverlappingWorldModels(std::vector<u32>& modelBits, const zeus::CAABox& aabb) const {
|
2022-07-26 05:08:14 +00:00
|
|
|
u32 bitmapWords = 0;
|
|
|
|
for (const CAreaListItem& item : x1c_areaListItems) {
|
|
|
|
if (item.x4_octTree != nullptr) {
|
|
|
|
bitmapWords += item.x4_octTree->x14_bitmapWordCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bitmapWords == 0u) {
|
|
|
|
modelBits.clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
modelBits.clear();
|
|
|
|
modelBits.resize(bitmapWords);
|
|
|
|
|
|
|
|
u32 curWord = 0;
|
|
|
|
for (const CAreaListItem& item : x1c_areaListItems) {
|
|
|
|
if (item.x4_octTree == nullptr) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
item.x4_octTree->FindOverlappingModels(modelBits.data() + curWord, aabb);
|
|
|
|
|
|
|
|
u32 wordModel = 0;
|
|
|
|
for (u32 i = 0; i < item.x4_octTree->x14_bitmapWordCount; ++i, wordModel += 32) {
|
|
|
|
u32& word = modelBits[curWord + i];
|
|
|
|
if (word == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (u32 j = 0; j < 32; ++j) {
|
|
|
|
if (((1U << j) & word) != 0) {
|
|
|
|
const zeus::CAABox& modelAABB = (*item.x10_models)[wordModel + j]->GetBounds();
|
|
|
|
if (!modelAABB.intersects(aabb)) {
|
|
|
|
word &= ~(1U << j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
curWord += item.x4_octTree->x14_bitmapWordCount;
|
|
|
|
}
|
2022-07-02 00:47:45 +00:00
|
|
|
}
|
|
|
|
|
2022-03-07 03:07:00 +00:00
|
|
|
s32 CCubeRenderer::DrawOverlappingWorldModelIDs(s32 alphaVal, const std::vector<u32>& modelBits,
|
2022-02-26 16:42:42 +00:00
|
|
|
const zeus::CAABox& aabb) {
|
2022-07-26 05:08:14 +00:00
|
|
|
SCOPED_GRAPHICS_DEBUG_GROUP("CCubeRenderer::DrawOverlappingWorldModelIDs", zeus::skGrey);
|
2022-03-07 03:07:00 +00:00
|
|
|
SetupRendererStates(true);
|
2022-07-26 05:08:14 +00:00
|
|
|
|
|
|
|
constexpr CModelFlags flags{0, 0, 3, zeus::skWhite};
|
|
|
|
|
|
|
|
u32 curWord = 0;
|
|
|
|
for (const CAreaListItem& item : x1c_areaListItems) {
|
|
|
|
if (item.x4_octTree == nullptr) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 wordModel = 0;
|
|
|
|
for (u32 i = 0; i < item.x4_octTree->x14_bitmapWordCount; ++i, wordModel += 32) {
|
|
|
|
const u32& word = modelBits[curWord + i];
|
|
|
|
if (word == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (u32 j = 0; j < 32; ++j) {
|
|
|
|
if (((1U << j) & word) != 0) {
|
|
|
|
if (alphaVal > 255) {
|
|
|
|
SetupCGraphicsState();
|
|
|
|
return alphaVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto& model = *(*item.x10_models)[wordModel + j];
|
|
|
|
GXSetDstAlpha(true, alphaVal);
|
|
|
|
CCubeMaterial::KillCachedViewDepState();
|
|
|
|
model.SetArraysCurrent();
|
|
|
|
for (const auto* surf = model.GetFirstUnsortedSurface(); surf != nullptr; surf = surf->GetNextSurface()) {
|
|
|
|
if (surf->GetBounds().intersects(aabb)) {
|
|
|
|
model.DrawSurface(*surf, flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
alphaVal += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
curWord += item.x4_octTree->x14_bitmapWordCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetupCGraphicsState();
|
|
|
|
return alphaVal;
|
2022-02-26 16:42:42 +00:00
|
|
|
}
|
2022-07-02 00:47:45 +00:00
|
|
|
|
2022-03-07 03:07:00 +00:00
|
|
|
void CCubeRenderer::DrawOverlappingWorldModelShadows(s32 alphaVal, const std::vector<u32>& modelBits,
|
2022-07-26 05:08:14 +00:00
|
|
|
const zeus::CAABox& aabb) {
|
|
|
|
SCOPED_GRAPHICS_DEBUG_GROUP("CBooRenderer::DrawOverlappingWorldModelShadows", zeus::skGrey);
|
|
|
|
|
|
|
|
u32 curWord = 0;
|
|
|
|
for (const CAreaListItem& item : x1c_areaListItems) {
|
|
|
|
if (item.x4_octTree == nullptr) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 wordModel = 0;
|
|
|
|
for (u32 i = 0; i < item.x4_octTree->x14_bitmapWordCount; ++i, wordModel += 32) {
|
|
|
|
const u32& word = modelBits[curWord + i];
|
|
|
|
if (word == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (u32 j = 0; j < 32; ++j) {
|
|
|
|
if (((1U << j) & word) != 0) {
|
|
|
|
if (alphaVal > 255) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto& model = *(*item.x10_models)[wordModel + j];
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetTevKColor(GX_KCOLOR0, zeus::CColor{0.f, static_cast<float>(alphaVal) / 255.f});
|
2022-07-26 05:08:14 +00:00
|
|
|
model.SetArraysCurrent();
|
|
|
|
for (const auto* surf = model.GetFirstUnsortedSurface(); surf != nullptr; surf = surf->GetNextSurface()) {
|
|
|
|
if (surf->GetBounds().intersects(aabb)) {
|
|
|
|
const auto& material = model.GetMaterialByIndex(surf->GetMaterialIndex());
|
|
|
|
CGX::SetVtxDescv_Compressed(material.GetVertexDesc());
|
|
|
|
CGX::CallDisplayList(surf->GetDisplayList(), surf->GetDisplayListSize());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
alphaVal += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
curWord += item.x4_octTree->x14_bitmapWordCount;
|
|
|
|
}
|
2022-07-02 00:47:45 +00:00
|
|
|
}
|
2022-03-06 04:50:54 +00:00
|
|
|
|
|
|
|
void CCubeRenderer::SetupCGraphicsState() {
|
|
|
|
CGraphics::DisableAllLights();
|
|
|
|
CGraphics::SetModelMatrix({});
|
|
|
|
CTevCombiners::ResetStates();
|
|
|
|
CGraphics::SetAmbientColor({0.4f});
|
2022-03-12 15:47:20 +00:00
|
|
|
CGX::SetChanMatColor(CGX::EChannelId::Channel0, zeus::skWhite);
|
2022-03-06 04:50:54 +00:00
|
|
|
CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, true);
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetChanCtrl(CGX::EChannelId::Channel1, false, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE);
|
2022-03-06 04:50:54 +00:00
|
|
|
CCubeMaterial::EnsureTevsDirect();
|
|
|
|
}
|
2022-03-06 07:46:42 +00:00
|
|
|
|
|
|
|
void CCubeRenderer::SetupRendererStates(bool depthWrite) {
|
|
|
|
CGraphics::DisableAllLights();
|
|
|
|
CGraphics::SetModelMatrix({});
|
2022-03-20 20:24:02 +00:00
|
|
|
CGraphics::SetAmbientColor(zeus::skClear);
|
2022-03-06 07:46:42 +00:00
|
|
|
CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, depthWrite);
|
|
|
|
CCubeMaterial::ResetCachedMaterials();
|
2022-07-29 20:16:55 +00:00
|
|
|
GXSetTevColor(GX_TEVREG1, to_gx_color(x2fc_tevReg1Color));
|
2022-03-06 07:46:42 +00:00
|
|
|
}
|
2022-05-13 23:40:19 +00:00
|
|
|
|
|
|
|
constexpr zeus::CTransform MvPostXf{
|
|
|
|
{zeus::CVector3f{0.5f, 0.f, 0.f}, {0.f, 0.f, 0.f}, {0.f, 0.5f, 0.f}},
|
|
|
|
{0.5f, 0.5f, 1.f},
|
|
|
|
};
|
|
|
|
|
|
|
|
void CCubeRenderer::DoThermalModelDraw(CCubeModel& model, const zeus::CColor& multCol, const zeus::CColor& addCol,
|
|
|
|
TConstVectorRef positions, TConstVectorRef normals, const CModelFlags& flags) {
|
|
|
|
SCOPED_GRAPHICS_DEBUG_GROUP("CCubeRenderer::DoThermalModelDraw", zeus::skBlue);
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX3x4, GX_TG_NRM, GX_TEXMTX0, true, GX_PTTEXMTX0);
|
2022-05-13 23:40:19 +00:00
|
|
|
CGX::SetNumTexGens(1);
|
|
|
|
CGX::SetNumChans(0);
|
2022-07-29 20:16:55 +00:00
|
|
|
x220_sphereRamp.Load(GX_TEXMAP0, EClampMode::Clamp);
|
2022-05-13 23:40:19 +00:00
|
|
|
zeus::CTransform xf = CGraphics::g_ViewMatrix.inverse().multiplyIgnoreTranslation(CGraphics::g_GXModelMatrix);
|
|
|
|
xf.origin.zeroOut();
|
2022-07-29 20:16:55 +00:00
|
|
|
GXLoadTexMtxImm(&xf, GX_TEXMTX0, GX_MTX3x4);
|
|
|
|
GXLoadTexMtxImm(&MvPostXf, GX_PTTEXMTX0, GX_MTX3x4);
|
|
|
|
CGX::SetStandardTevColorAlphaOp(GX_TEVSTAGE0);
|
|
|
|
CGX::SetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_C0, GX_CC_TEXC, GX_CC_KONST);
|
|
|
|
CGX::SetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_TEXA, GX_CA_A0, GX_CA_KONST);
|
|
|
|
CGX::SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
|
2022-05-13 23:40:19 +00:00
|
|
|
CGX::SetNumTevStages(1);
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetTevKColor(GX_KCOLOR0, addCol);
|
|
|
|
CGX::SetTevKColorSel(GX_TEVSTAGE0, GX_TEV_KCSEL_K0);
|
|
|
|
CGX::SetTevKAlphaSel(GX_TEVSTAGE0, GX_TEV_KASEL_K0_A);
|
|
|
|
GXSetTevColor(GX_TEVREG0, to_gx_color(multCol));
|
|
|
|
CGX::SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0);
|
|
|
|
CGX::SetBlendMode(GX_BM_BLEND, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR);
|
|
|
|
CGX::SetZMode(flags.x2_flags.IsSet(CModelFlagBits::DepthTest), GX_LEQUAL,
|
2022-05-13 23:40:19 +00:00
|
|
|
flags.x2_flags.IsSet(CModelFlagBits::DepthUpdate));
|
|
|
|
model.DrawFlat(positions, normals,
|
2022-07-02 00:47:45 +00:00
|
|
|
flags.x2_flags.IsSet(CModelFlagBits::ThermalUnsortedOnly) ? ESurfaceSelection::Unsorted
|
|
|
|
: ESurfaceSelection::All);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CCubeRenderer::ReallyDrawSpaceWarp(const zeus::CVector3f& pt, float strength) {
|
2022-07-26 05:08:14 +00:00
|
|
|
return; // TODO
|
|
|
|
|
|
|
|
float vpLeft = static_cast<float>(CGraphics::GetViewportLeft());
|
|
|
|
float vpTop = static_cast<float>(CGraphics::GetViewportTop());
|
|
|
|
float vpHalfWidth = static_cast<float>(CGraphics::GetViewportWidth() / 2);
|
|
|
|
float vpHalfHeight = static_cast<float>(CGraphics::GetViewportHeight() / 2);
|
|
|
|
float local_100 = vpLeft + vpHalfWidth * pt.x() + vpHalfWidth;
|
|
|
|
float local_fc = vpTop + vpHalfHeight * -pt.y() + vpHalfHeight;
|
|
|
|
zeus::CVector2i CStack264{static_cast<s32>(local_100) & ~3, static_cast<s32>(local_fc) & ~3};
|
|
|
|
auto v2right = CStack264 - zeus::CVector2i{96, 96};
|
|
|
|
auto v2left = CStack264 + zeus::CVector2i{96, 96};
|
|
|
|
zeus::CVector2f uv1min{0.f, 0.f};
|
|
|
|
zeus::CVector2f uv1max{1.f, 1.f};
|
|
|
|
|
|
|
|
s32 aleft = CGraphics::GetViewportLeft() & ~3;
|
|
|
|
s32 atop = CGraphics::GetViewportTop() & ~3;
|
|
|
|
s32 aright = (CGraphics::GetViewportLeft() + CGraphics::GetViewportWidth() + 3) & ~3;
|
|
|
|
s32 abottom = (CGraphics::GetViewportTop() + CGraphics::GetViewportHeight() + 3) & ~3;
|
|
|
|
if (v2right.x < aleft) {
|
|
|
|
uv1min.x() = static_cast<float>(aleft - v2right.x) * 0.005208333f;
|
|
|
|
v2right.x = aleft;
|
|
|
|
}
|
|
|
|
if (v2right.y < atop) {
|
|
|
|
uv1min.y() = static_cast<float>(atop - v2right.x) * 0.005208333f;
|
|
|
|
v2right.y = atop;
|
|
|
|
}
|
|
|
|
if (v2left.x > aright) {
|
|
|
|
uv1max.x() = 1.f - static_cast<float>(v2left.x - aright) * 0.005208333f;
|
|
|
|
v2left.x = aright;
|
|
|
|
}
|
|
|
|
if (v2left.y > abottom) {
|
|
|
|
uv1max.y() = 1.f - static_cast<float>(v2left.y - abottom) * 0.005208333f;
|
|
|
|
v2left.y = abottom;
|
|
|
|
}
|
|
|
|
const auto v2sub = v2left - v2right;
|
|
|
|
if (v2sub.x > 0 && v2sub.y > 0) {
|
2022-07-29 20:16:55 +00:00
|
|
|
GXFogType fogType;
|
2022-07-26 05:08:14 +00:00
|
|
|
float fogStartZ;
|
|
|
|
float fogEndZ;
|
|
|
|
float fogNearZ;
|
|
|
|
float fogFarZ;
|
|
|
|
GXColor fogColor;
|
|
|
|
CGX::GetFog(&fogType, &fogStartZ, &fogEndZ, &fogNearZ, &fogFarZ, &fogColor);
|
2022-07-29 20:16:55 +00:00
|
|
|
CGX::SetFog(GX_FOG_NONE, fogStartZ, fogEndZ, fogNearZ, fogFarZ, fogColor);
|
2022-08-09 06:10:51 +00:00
|
|
|
GXSetTexCopySrc(v2right.x, v2right.y, v2sub.x, v2sub.y);
|
|
|
|
GXSetTexCopyDst(v2sub.x, v2sub.y, GX_TF_RGBA8, false);
|
|
|
|
GXCopyTex(CGraphics::sSpareTextureData, false);
|
|
|
|
GXPixModeSync();
|
|
|
|
CGraphics::LoadDolphinSpareTexture(v2sub.x, v2sub.y, GX_TF_RGBA8, nullptr, GX_TEXMAP7);
|
2022-07-29 20:16:55 +00:00
|
|
|
x150_reflectionTex.Load(GX_TEXMAP1, EClampMode::Clamp);
|
|
|
|
CGX::SetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_TEXC);
|
|
|
|
CGX::SetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, true, GX_TEVPREV);
|
|
|
|
CGX::SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX3x4, GX_TG_TEX0, GX_IDENTITY, false, GX_PTIDENTITY);
|
|
|
|
CGX::SetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX3x4, GX_TG_TEX1, GX_IDENTITY, false, GX_PTIDENTITY);
|
|
|
|
CGX::SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP7, GX_COLOR_NULL);
|
2022-07-26 05:08:14 +00:00
|
|
|
}
|
2022-07-02 00:47:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CCubeRenderer::ReallyRenderFogVolume(const zeus::CColor& color, const zeus::CAABox& aabb, const CModel* model,
|
|
|
|
const CSkinnedModel* sModel) {
|
|
|
|
// TODO
|
2022-05-13 23:40:19 +00:00
|
|
|
}
|
2022-02-25 07:45:25 +00:00
|
|
|
} // namespace metaforce
|