metaforce/visigen/VISIBuilder.hpp

118 lines
3.3 KiB
C++
Raw Normal View History

2018-10-07 03:42:33 +00:00
#pragma once
2017-02-24 08:28:44 +00:00
#include "VISIRenderer.hpp"
#include "zeus/CAABox.hpp"
2022-02-18 00:38:31 +00:00
#include "xxhash.h"
2017-02-24 08:28:44 +00:00
#include "athena/MemoryWriter.hpp"
#include <unordered_map>
2017-10-24 03:12:10 +00:00
#ifdef _WIN32
using ProcessType = HANDLE;
#else
using ProcessType = pid_t;
#endif
2018-12-08 05:30:43 +00:00
namespace std {
template <>
struct hash<zeus::CVector3f> {
size_t operator()(const zeus::CVector3f& val) const noexcept {
zeus::simd_floats f(val.mSimd);
return XXH64(&f[0], 12, 0);
}
2017-02-24 08:28:44 +00:00
};
2018-12-08 05:30:43 +00:00
} // namespace std
struct VISIBuilder {
struct Leaf {
std::vector<uint8_t> bits;
void setBit(size_t bit) {
size_t byte = bit / 8;
if (byte >= bits.size())
bits.resize(byte + 1);
bits[byte] |= 1 << (bit & 0x7);
}
void setLightEnum(size_t bit, EPVSVisSetState state) {
size_t byte0 = bit / 8;
size_t byte1 = (bit + 1) / 8;
if (byte1 >= bits.size())
bits.resize(byte1 + 1);
if (byte0 == byte1) {
bits[byte0] |= int(state) << (bit & 0x7);
} else {
bits[byte0] |= (int(state) << 7) & 0x1;
bits[byte1] |= (int(state) >> 1) & 0x1;
}
}
bool operator==(const Leaf& other) const {
if (bits.size() != other.bits.size())
return false;
if (memcmp(bits.data(), other.bits.data(), bits.size()))
return false;
return true;
}
Leaf& operator|=(const Leaf& other) {
if (bits.size() < other.bits.size())
bits.resize(other.bits.size());
for (size_t i = 0; i < other.bits.size(); ++i)
2018-12-08 05:30:43 +00:00
bits[i] |= other.bits[i];
return *this;
}
operator bool() const { return bits.size() != 0; }
2017-02-24 08:28:44 +00:00
2018-12-08 05:30:43 +00:00
void write(athena::io::MemoryWriter& w, size_t leafBytes) const {
for (size_t i = 0; i < leafBytes; ++i) {
if (i < bits.size())
w.writeUByte(bits[i]);
else
w.writeUByte(0);
}
}
};
2017-02-24 08:28:44 +00:00
2018-12-08 05:30:43 +00:00
class PVSRenderCache {
friend struct VISIBuilder;
VISIRenderer& m_renderer;
std::unordered_map<zeus::CVector3f, std::unique_ptr<Leaf>> m_cache;
size_t m_lightMetaBit;
2017-02-24 08:28:44 +00:00
2018-12-08 05:30:43 +00:00
public:
PVSRenderCache(VISIRenderer& renderer);
const Leaf& GetLeaf(const zeus::CVector3f& vec);
} renderCache;
2017-02-24 08:28:44 +00:00
2018-12-08 05:30:43 +00:00
class Progress {
float m_prog = 0.f;
FPercent m_updatePercent;
2017-02-24 08:28:44 +00:00
2018-12-08 05:30:43 +00:00
public:
void report(int divisions);
Progress(FPercent updatePercent) : m_updatePercent(updatePercent) {}
};
2017-02-24 08:28:44 +00:00
2018-12-08 05:30:43 +00:00
struct Node {
std::vector<Node> childNodes;
size_t childRelOffs[8] = {};
Leaf leaf;
uint8_t flags = 0;
2017-02-24 08:28:44 +00:00
2018-12-08 05:30:43 +00:00
void buildChildren(int level, int divisions, const zeus::CAABox& curAabb, PVSRenderCache& rc, Progress& prog,
const std::function<bool()>& terminate);
void calculateSizesAndOffs(size_t& cur, size_t leafSz);
void writeNodes(athena::io::MemoryWriter& w, size_t leafBytes) const;
2017-02-24 08:28:44 +00:00
2018-12-08 05:30:43 +00:00
bool operator==(const Node& other) const {
if ((flags & 0x7) || (other.flags & 0x7))
return false;
return leaf == other.leaf;
}
} rootNode;
2017-02-24 08:28:44 +00:00
2018-12-08 05:30:43 +00:00
std::vector<uint8_t> build(const zeus::CAABox& fullAabb, size_t modelCount,
const std::vector<VISIRenderer::Entity>& entities,
const std::vector<VISIRenderer::Light>& lights, size_t layer2LightCount,
FPercent updatePercent, ProcessType parentPid);
2017-02-24 08:28:44 +00:00
2018-12-08 05:30:43 +00:00
VISIBuilder(VISIRenderer& renderer) : renderCache(renderer) {}
2017-02-24 08:28:44 +00:00
};