Files
2026-05-21 15:37:31 -07:00

221 lines
7.8 KiB
C++

/*
===========================================================================
Radiant masked occlusion culling bridge
===========================================================================
*/
#include "gl_radiant_moc.h"
#define USE_D3D 0
#define USE_AVX512 0
#include "thirdparty/MaskedOcclusionCulling/MaskedOcclusionCulling.h"
#include <algorithm>
namespace {
struct radiantMOCState_t {
MaskedOcclusionCulling* moc;
unsigned int width;
unsigned int height;
bool active;
qglRadiantMOCStats_t stats;
};
radiantMOCState_t s_radiantMOC = {};
static unsigned int RadiantMOC_RoundUp(unsigned int value, unsigned int alignment) {
return (value + alignment - 1) & ~(alignment - 1);
}
static radiantMOCState_t* RadiantMOC_FromContext(qglMOCContext_t context) {
return reinterpret_cast<radiantMOCState_t*>(context);
}
} // namespace
qglMOCContext_t QGL_MOC_Create() {
radiantMOCState_t* context = new radiantMOCState_t;
context->moc = NULL;
context->width = 0;
context->height = 0;
context->active = false;
context->stats.occluderTriangles = 0;
context->stats.testedRects = 0;
context->stats.occludedRects = 0;
return context;
}
void QGL_MOC_Destroy(qglMOCContext_t context) {
radiantMOCState_t* state = RadiantMOC_FromContext(context);
if (state == NULL) {
return;
}
if (state->moc != NULL) {
MaskedOcclusionCulling::Destroy(state->moc);
state->moc = NULL;
}
delete state;
}
bool QGL_MOC_BeginFrame(qglMOCContext_t context, int width, int height, float nearClip) {
radiantMOCState_t* state = RadiantMOC_FromContext(context);
if (state == NULL) {
return false;
}
const unsigned int mocWidth = RadiantMOC_RoundUp(std::max(width, 64), 8);
const unsigned int mocHeight = RadiantMOC_RoundUp(std::max(height, 64), 4);
if (state->moc == NULL) {
state->moc = MaskedOcclusionCulling::Create(MaskedOcclusionCulling::AVX2);
}
if (state->moc == NULL) {
state->active = false;
return false;
}
if (state->width != mocWidth || state->height != mocHeight) {
state->moc->SetResolution(mocWidth, mocHeight);
state->width = mocWidth;
state->height = mocHeight;
}
state->moc->SetNearClipPlane(nearClip);
state->moc->ClearBuffer();
state->active = true;
state->stats.occluderTriangles = 0;
state->stats.testedRects = 0;
state->stats.occludedRects = 0;
return true;
}
void QGL_MOC_EndFrame(qglMOCContext_t context) {
radiantMOCState_t* state = RadiantMOC_FromContext(context);
if (state != NULL) {
state->active = false;
}
}
bool QGL_MOC_IsActive(qglMOCContext_t context) {
radiantMOCState_t* state = RadiantMOC_FromContext(context);
return state != NULL && state->active && state->moc != NULL;
}
void QGL_MOC_RenderTriangles(qglMOCContext_t context, const qglRadiantMOCClipVertex_t* verts, const unsigned int* indices, int numTriangles) {
radiantMOCState_t* state = RadiantMOC_FromContext(context);
if (!QGL_MOC_IsActive(context) || verts == NULL || indices == NULL || numTriangles <= 0) {
return;
}
MaskedOcclusionCulling::VertexLayout layout(sizeof(qglRadiantMOCClipVertex_t), 4, 8);
state->moc->RenderTriangles(&verts[0].x, indices, numTriangles, NULL, MaskedOcclusionCulling::BACKFACE_NONE, MaskedOcclusionCulling::CLIP_PLANE_ALL, layout);
state->stats.occluderTriangles += numTriangles;
}
bool QGL_MOC_TestTriangles(qglMOCContext_t context, const qglRadiantMOCClipVertex_t* verts, const unsigned int* indices, int numTriangles) {
radiantMOCState_t* state = RadiantMOC_FromContext(context);
if (!QGL_MOC_IsActive(context) || verts == NULL || indices == NULL || numTriangles <= 0) {
return true;
}
MaskedOcclusionCulling::VertexLayout layout(sizeof(qglRadiantMOCClipVertex_t), 4, 8);
state->stats.testedRects++;
const MaskedOcclusionCulling::CullingResult result = state->moc->TestTriangles(&verts[0].x, indices, numTriangles, NULL, MaskedOcclusionCulling::BACKFACE_NONE, MaskedOcclusionCulling::CLIP_PLANE_ALL, layout);
if (result == MaskedOcclusionCulling::OCCLUDED || result == MaskedOcclusionCulling::VIEW_CULLED) {
state->stats.occludedRects++;
return false;
}
return true;
}
void QGL_MOC_RenderIndexedTriangles(qglMOCContext_t context, const float* verts, const unsigned int* indices, int numTriangles, const float* modelToClipMatrix, int vertexStride, int yOffset, int zOffset) {
radiantMOCState_t* state = RadiantMOC_FromContext(context);
if (!QGL_MOC_IsActive(context) || verts == NULL || indices == NULL || numTriangles <= 0 || modelToClipMatrix == NULL) {
return;
}
MaskedOcclusionCulling::VertexLayout layout(vertexStride, yOffset, zOffset);
state->moc->RenderTriangles(verts, indices, numTriangles, modelToClipMatrix, MaskedOcclusionCulling::BACKFACE_NONE, MaskedOcclusionCulling::CLIP_PLANE_ALL, layout);
state->stats.occluderTriangles += numTriangles;
}
bool QGL_MOC_TestIndexedTriangles(qglMOCContext_t context, const float* verts, const unsigned int* indices, int numTriangles, const float* modelToClipMatrix, int vertexStride, int yOffset, int zOffset) {
radiantMOCState_t* state = RadiantMOC_FromContext(context);
if (!QGL_MOC_IsActive(context) || verts == NULL || indices == NULL || numTriangles <= 0 || modelToClipMatrix == NULL) {
return true;
}
MaskedOcclusionCulling::VertexLayout layout(vertexStride, yOffset, zOffset);
state->stats.testedRects++;
const MaskedOcclusionCulling::CullingResult result = state->moc->TestTriangles(verts, indices, numTriangles, modelToClipMatrix, MaskedOcclusionCulling::BACKFACE_NONE, MaskedOcclusionCulling::CLIP_PLANE_ALL, layout);
if (result == MaskedOcclusionCulling::OCCLUDED || result == MaskedOcclusionCulling::VIEW_CULLED) {
state->stats.occludedRects++;
return false;
}
return true;
}
bool QGL_MOC_TestRect(qglMOCContext_t context, float xmin, float ymin, float xmax, float ymax, float wmin) {
radiantMOCState_t* state = RadiantMOC_FromContext(context);
if (!QGL_MOC_IsActive(context)) {
return true;
}
state->stats.testedRects++;
const MaskedOcclusionCulling::CullingResult result = state->moc->TestRect(xmin, ymin, xmax, ymax, wmin);
if (result == MaskedOcclusionCulling::OCCLUDED || result == MaskedOcclusionCulling::VIEW_CULLED) {
state->stats.occludedRects++;
return false;
}
return true;
}
qglRadiantMOCStats_t QGL_MOC_GetStats(qglMOCContext_t context) {
radiantMOCState_t* state = RadiantMOC_FromContext(context);
if (state == NULL) {
qglRadiantMOCStats_t emptyStats = {};
return emptyStats;
}
return state->stats;
}
bool QGL_RadiantMOC_BeginFrame(int width, int height, float nearClip) {
return QGL_MOC_BeginFrame(&s_radiantMOC, width, height, nearClip);
}
void QGL_RadiantMOC_EndFrame() {
QGL_MOC_EndFrame(&s_radiantMOC);
}
bool QGL_RadiantMOC_IsActive() {
return QGL_MOC_IsActive(&s_radiantMOC);
}
void QGL_RadiantMOC_RenderTriangles(const qglRadiantMOCClipVertex_t* verts, const unsigned int* indices, int numTriangles) {
QGL_MOC_RenderTriangles(&s_radiantMOC, verts, indices, numTriangles);
}
bool QGL_RadiantMOC_TestTriangles(const qglRadiantMOCClipVertex_t* verts, const unsigned int* indices, int numTriangles) {
return QGL_MOC_TestTriangles(&s_radiantMOC, verts, indices, numTriangles);
}
void QGL_RadiantMOC_RenderIndexedTriangles(const float* verts, const unsigned int* indices, int numTriangles, const float* modelToClipMatrix, int vertexStride, int yOffset, int zOffset) {
QGL_MOC_RenderIndexedTriangles(&s_radiantMOC, verts, indices, numTriangles, modelToClipMatrix, vertexStride, yOffset, zOffset);
}
bool QGL_RadiantMOC_TestIndexedTriangles(const float* verts, const unsigned int* indices, int numTriangles, const float* modelToClipMatrix, int vertexStride, int yOffset, int zOffset) {
return QGL_MOC_TestIndexedTriangles(&s_radiantMOC, verts, indices, numTriangles, modelToClipMatrix, vertexStride, yOffset, zOffset);
}
bool QGL_RadiantMOC_TestRect(float xmin, float ymin, float xmax, float ymax, float wmin) {
return QGL_MOC_TestRect(&s_radiantMOC, xmin, ymin, xmax, ymax, wmin);
}
qglRadiantMOCStats_t QGL_RadiantMOC_GetStats() {
return s_radiantMOC.stats;
}