metaforce/Runtime/Graphics/CCubeRenderer.cpp

181 lines
6.7 KiB
C++

#include "CCubeRenderer.hpp"
#include "GameGlobalObjects.hpp"
#include "Graphics/CDrawable.hpp"
#include "Graphics/CDrawablePlaneObject.hpp"
#include "Graphics/CLight.hpp"
namespace metaforce {
static logvisor::Module Log("CCubeRenderer");
static rstl::reserved_vector<CDrawable, 512> sDataHolder;
static rstl::reserved_vector<rstl::reserved_vector<CDrawable*, 128>, 50> sBucketsHolder;
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;
static inline rstl::reserved_vector<rstl::reserved_vector<CDrawable*, 128>, 50>* sBuckets = nullptr;
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};
static inline std::array sMinMaxDistance{0.0f, 0.0f};
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();
for (rstl::reserved_vector<CDrawable*, 128>& bucket : *sBuckets) {
bucket.clear();
}
sMinMaxDistance = skWorstMinMaxDistance;
}
void Buckets::Sort() {
float delta = std::max(1.f, sMinMaxDistance[1] - sMinMaxDistance[0]);
float pitch = 49.f / delta;
for (auto it = sPlaneObjectData->begin(); it != sPlaneObjectData->end(); ++it)
if (sPlaneObjectBucket->size() != sPlaneObjectBucket->capacity())
sPlaneObjectBucket->push_back(s16(it - sPlaneObjectData->begin()));
u32 precision = 50;
if (sPlaneObjectBucket->size()) {
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));
int accum = 0;
for (u16 idx : *sPlaneObjectBucket) {
++accum;
CDrawablePlaneObject& planeObj = (*sPlaneObjectData)[idx];
planeObj.x24_targetBucket = u16(precision * accum);
}
}
for (CDrawable& drawable : *sData) {
int slot;
float relDist = drawable.GetDistance() - sMinMaxDistance[0];
if (sPlaneObjectBucket->empty()) {
slot = zeus::clamp(1, int(relDist * pitch), 49);
} else {
slot = zeus::clamp(0, int(relDist * pitch), int(precision) - 2);
for (u16 idx : *sPlaneObjectBucket) {
CDrawablePlaneObject& planeObj = (*sPlaneObjectData)[idx];
bool partial, full;
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;
}
bool cont;
if (drawable.GetType() == EDrawableType::Particle)
cont = planeObj.x3c_24_invertTest ? !partial : full;
else
cont = planeObj.x3c_24_invertTest ? (!partial || !full) : (partial || full);
if (!cont)
break;
slot += precision;
}
}
if (slot == -1)
slot = 49;
rstl::reserved_vector<CDrawable*, 128>& bucket = (*sBuckets)[slot];
if (bucket.size() < bucket.capacity())
bucket.push_back(&drawable);
// 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);
rstl::reserved_vector<CDrawable*, 128>& bucket = *it;
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];
rstl::reserved_vector<CDrawable*, 128>& bucket = (*sBuckets)[planeObj.x24_targetBucket];
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;
}
CCubeRenderer::CCubeRenderer(IObjectStore& store, IFactory& resFac) : x8_factory(resFac), xc_store(store) {
// void* data = xe4_blackTex.GetBitMapData();
// memset(data, 0, 32);
// xe4_blackTex.UnLock();
GenerateReflectionTex();
GenerateFogVolumeRampTex();
GenerateSphereRampTex();
LoadThermoPalette();
g_Renderer = this;
Buckets::Init();
// GX draw sync
}
} // namespace metaforce